Skip to content

FormulaConfigurationAPI

Paulo Gomes da Cruz Junior edited this page Sep 11, 2026 · 1 revision

API: Formula Configuration

Type: API Domain: Configuration — Formula Sets Base path: /api/configuration/formulas Authentication: Bearer JWT (ADMIN role required) Last updated: 2026-09-10 Status: Current

Overview

The Formula Configuration API manages formula sets with a date-effective lifecycle. Each formula set belongs to an area (INTERIOR or COASTAL), has a start date, an optional end date (null = open-ended), and contains an ordered list of formulas. The API supports complete-set PUT updates (idempotent replacement) and date-effective reads for downstream calculation services.

Endpoints

GET /api/configuration/formulas

Retrieves a paginated list of all formula sets.

Query Parameters

Parameter In Type Required Description
page query integer no Page number (0-based, default: 0)
size query integer no Items per page (default: 20, max: 100)
sort query string[] no Sort criteria (default: startDate,DESC)

Response 200 OK

{
  "content": [
    {
      "id": 1,
      "area": "INTERIOR",
      "startDate": "2026-01-01",
      "endDate": null,
      "deleted": false,
      "formulas": [
        {
          "formulaKey": "da.mature.avoidableGradeY",
          "expression": "da.mature.merchantableVolume * 0.15",
          "declaredVariables": ["da.mature.merchantableVolume"],
          "validationErrors": [],
          "sortOrder": 1
        }
      ],
      "createdAt": "2026-01-01T10:00:00Z",
      "updatedAt": "2026-01-01T10:00:00Z"
    }
  ],
  "page": {
    "number": 0,
    "size": 20,
    "totalElements": 1,
    "totalPages": 1
  }
}

Error Responses

Status When Body (type field)
401 Missing or invalid token /errors/unauthorized
403 Insufficient permissions (not ADMIN) /errors/forbidden
500 Server error /errors/internal

GET /api/configuration/formulas/{date}/{area}

Retrieves the formula set effective for the given date and area. This is the date-effective lookup used by calculation engines.

Path Parameters

Parameter Type Required Description
date string (YYYY-MM-DD) yes Effective date
area string (INTERIOR | COASTAL) yes Geographic area

Response 200 OK

{
  "id": 1,
  "area": "INTERIOR",
  "startDate": "2026-01-01",
  "endDate": null,
  "deleted": false,
  "formulas": [
    {
      "formulaKey": "da.mature.avoidableGradeY",
      "expression": "da.mature.merchantableVolume * 0.15",
      "declaredVariables": ["da.mature.merchantableVolume"],
      "validationErrors": [],
      "sortOrder": 1
    }
  ],
  "createdAt": "2026-01-01T10:00:00Z",
  "updatedAt": "2026-01-01T10:00:00Z"
}

Error Responses

Status When Body (type field)
400 Invalid date format or area https://example.com/problem/invalid-parameters
404 No formula set effective for date/area https://example.com/problem/not-found
401 Missing or invalid token /errors/unauthorized
403 Insufficient permissions /errors/forbidden

400 Example

{
  "type": "https://example.com/problem/invalid-parameters",
  "title": "Invalid Parameters",
  "status": 400,
  "detail": "Invalid date format or area. Expected date (YYYY-MM-DD) and area (INTERIOR|COASTAL).",
  "instance": "/api/configuration/formulas/invalid"
}

404 Example

{
  "type": "https://example.com/problem/not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "No formula set found effective for date 2020-01-01 and area INTERIOR",
  "instance": "/api/configuration/formulas/2020-01-01/INTERIOR"
}

POST /api/configuration/formulas

Creates a new formula set. The backend assigns id, createdAt, updatedAt, and sets deleted: false.

Request Body (FormulaSetRequest)

{
  "area": "INTERIOR",
  "startDate": "2026-09-10",
  "endDate": null,
  "formulas": [
    {
      "formulaKey": "da.mature.avoidableGradeY",
      "expression": "da.mature.merchantableVolume * 0.15",
      "declaredVariables": ["da.mature.merchantableVolume"],
      "validationErrors": [],
      "sortOrder": 1
    }
  ]
}

Response 201 Created

{
  "id": 10,
  "area": "INTERIOR",
  "startDate": "2026-09-10",
  "endDate": null,
  "deleted": false,
  "formulas": [
    {
      "formulaKey": "da.mature.avoidableGradeY",
      "expression": "da.mature.merchantableVolume * 0.15",
      "declaredVariables": ["da.mature.merchantableVolume"],
      "validationErrors": [],
      "sortOrder": 1
    }
  ],
  "createdAt": "2026-09-10T10:00:00Z",
  "updatedAt": "2026-09-10T10:00:00Z"
}

Headers

  • Location: /api/configuration/formulas/10

Error Responses

Status When Body (type field)
400 Invalid request body /errors/bad-request
401 Missing or invalid token /errors/unauthorized
403 Insufficient permissions /errors/forbidden
422 Validation failed (one or more formulas invalid) https://example.com/problem/validation-failed

422 Example

{
  "type": "https://example.com/problem/validation-failed",
  "title": "Validation Failed",
  "status": 422,
  "detail": "One or more formulas failed validation",
  "instance": "/api/configuration/formulas",
  "validationErrors": [
    {
      "formulaKey": "da.mature.avoidableGradeY",
      "errors": [
        {
          "code": "UNKNOWN_VARIABLE",
          "message": "Unknown variable: da.mature.avoidableGradeY",
          "startOffset": 0,
          "endOffset": 24
        }
      ]
    }
  ]
}

PUT /api/configuration/formulas/{id}

Updates a formula set with a complete replacement (idempotent). The entire formula set is replaced — this is not a partial update.

Path Parameters

Parameter Type Required Description
id integer yes Formula set ID

Request Body (FormulaSetRequest — complete set)

{
  "area": "INTERIOR",
  "startDate": "2026-09-10",
  "endDate": "2026-12-31",
  "formulas": [
    {
      "formulaKey": "da.mature.avoidableGradeY",
      "expression": "da.mature.merchantableVolume * 0.15",
      "declaredVariables": ["da.mature.merchantableVolume"],
      "validationErrors": [],
      "sortOrder": 1
    },
    {
      "formulaKey": "da.immature.wasteFactor",
      "expression": "da.immature.merchantableVolume * 0.05",
      "declaredVariables": ["da.immature.merchantableVolume"],
      "validationErrors": [],
      "sortOrder": 2
    }
  ]
}

Response 200 OK

{
  "id": 5,
  "area": "INTERIOR",
  "startDate": "2026-09-10",
  "endDate": "2026-12-31",
  "deleted": false,
  "formulas": [
    {
      "formulaKey": "da.mature.avoidableGradeY",
      "expression": "da.mature.merchantableVolume * 0.15",
      "declaredVariables": ["da.mature.merchantableVolume"],
      "validationErrors": [],
      "sortOrder": 1
    },
    {
      "formulaKey": "da.immature.wasteFactor",
      "expression": "da.immature.merchantableVolume * 0.05",
      "declaredVariables": ["da.immature.merchantableVolume"],
      "validationErrors": [],
      "sortOrder": 2
    }
  ],
  "createdAt": "2026-09-10T10:00:00Z",
  "updatedAt": "2026-09-10T10:00:00Z"
}

Error Responses

| Status | When | Body (type field) |

Error Responses

Status When Body (type field)
400 Invalid request body /errors/bad-request
401 Missing or invalid token /errors/unauthorized
403 Insufficient permissions /errors/forbidden
404 Formula set not found https://example.com/problem/not-found
409 Conflict: future open-ended set already exists for area https://example.com/problem/conflict
422 Validation failed or lifecycle rule violation https://example.com/problem/validation-failed or https://example.com/problem/invalid-state

409 Example

{
  "type": "https://example.com/problem/conflict",
  "title": "Conflict",
  "status": 409,
  "detail": "A future open-ended formula set already exists for this area. Delete it first or adjust the start date.",
  "instance": "/api/configuration/formulas/5"
}

DELETE /api/configuration/formulas/{id}

Soft-deletes a future open-ended formula set. Only sets with startDate > today (business date) and endDate === null can be deleted. Deleting reopens the predecessor by clearing its end date.

Path Parameters

Parameter Type Required Description
id integer yes Formula set ID

Response 204 No Content

Error Responses

Status When Body (type field)
401 Missing or invalid token /errors/unauthorized
403 Insufficient permissions /errors/forbidden
404 Formula set not found https://example.com/problem/not-found
422 Not a future open-ended set https://example.com/problem/invalid-state

422 Example

{
  "type": "https://example.com/problem/invalid-state",
  "title": "Invalid State",
  "status": 422,
  "detail": "Only future open-ended formula sets can be deleted",
  "instance": "/api/configuration/formulas/1"
}

Common Error Format

All errors follow RFC 7807 Problem Details:

{
  "type": "https://example.com/problem/{error-type}",
  "title": "Error Title",
  "status": 422,
  "detail": "Human-readable description",
  "instance": "/api/configuration/formulas/5",
  "validationErrors": [...]
}

Authentication

  • Mechanism: Bearer JWT in Authorization header
  • Required Role: ADMIN (checked by backend authorization)
  • Feature Flag: configuration-enabled (checked by backend)
  • Token Format: Standard JWT with realm_access.roles claim
  • Expiry/Refresh: Handled by auth interceptor; 401 triggers redirect to /unauthorized

Rate Limiting

None applied specifically to these endpoints. Global API rate limits may apply.

OpenAPI Spec

No dedicated OpenAPI spec file. The API contract is defined by:

  • TypeScript DTOs in src/services/formulaConfiguration.types.ts
  • Service methods in src/services/formulaConfiguration.service.ts
  • Wiremock stubs in frontend/stub/mappings/formula-configuration.json

Known Drift: None — TypeScript types are the source of truth for frontend.

Lifecycle Rules

Rule Enforcement
Only one future open-ended set per area Backend returns 409 on create/update
Future open-ended = startDate > today AND endDate === null Backend validation
Soft-delete only allowed on future open-ended Backend returns 422 otherwise
Delete reopens predecessor (clears endDate) Backend transaction
Date-effective lookup: latest set where startDate <= date AND (endDate >= date OR endDate === null) AND !deleted Backend query

Wiremock Stubs

All endpoints mocked in frontend/stub/mappings/formula-configuration.json with:

  • Success responses for all CRUD operations
  • Error responses for 400, 404, 409, 422
  • Dynamic body templating via jsonPath

Related Pages

Waste Plus Wiki

Home

Architecture

Codes

Decisions

Knowledge Base

Development

Changes

Clone this wiki locally