Repository navigation
FormulaConfigurationAPI
Type: API Domain: Configuration — Formula Sets Base path:
/api/configuration/formulasAuthentication: Bearer JWT (ADMIN role required) Last updated: 2026-09-10 Status: Current
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.
Retrieves a paginated list of all formula sets.
| 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
}
}| Status | When | Body (type field) |
|---|---|---|
401 |
Missing or invalid token | /errors/unauthorized |
403 |
Insufficient permissions (not ADMIN) | /errors/forbidden |
500 |
Server error | /errors/internal |
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"
}| 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 |
{
"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"
}{
"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"
}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"
}Location: /api/configuration/formulas/10
| 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 |
{
"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
}
]
}
]
}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) |
| 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
|
{
"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"
}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 |
| 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 |
{
"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"
}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": [...]
}-
Mechanism: Bearer JWT in
Authorizationheader -
Required Role:
ADMIN(checked by backend authorization) -
Feature Flag:
configuration-enabled(checked by backend) -
Token Format: Standard JWT with
realm_access.rolesclaim -
Expiry/Refresh: Handled by auth interceptor; 401 triggers redirect to
/unauthorized
None applied specifically to these endpoints. Global API rate limits may apply.
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.
| 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 |
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
- FormulaConfigurationService — Frontend API client
- FormulaConfigurationList — List page (GET list)
- FormulaConfigurationDetail — Detail page (GET effective, POST, PUT, DELETE)
- FormulaConfigurationHooks — TanStack Query hooks
- FormulaEditorPattern — FormulaInput integration pattern
This wiki documents NR Waste Plus for users and developers. Verify security and deployment guidance against the current application configuration before applying it elsewhere.
- Report an issue or ask a question in the GitHub repository.
- Follow the Contributing Guidelines to propose an update.
- Read the Code of Conduct.
Collection indexes support human browsing and machine retrieval. Keep both current when adding or moving wiki pages.
NR Waste Plus Wiki | GitHub Repository