Task and Taxonomy API Reference¶
The API manages tasks, reusable tags, and hierarchical nomenclatures at the
singular paths /api/v1/task, /api/v1/tag, and /api/v1/nomenclature.
Swagger UI is published at /swagger-ui.html.
All business endpoints require JWT authentication. Obtain a token with
POST /api/v1/auth/login, then send it as Authorization: Bearer <token>. The
forced administrator account is configured with APP_ADMIN_USERNAME and
APP_ADMIN_PASSWORD at API startup.
Resource Schemas¶
Shared Fields¶
Tasks, tags, and nomenclatures share these identity, business, and audit fields.
| Field | JSON type | Required | Rules |
|---|---|---|---|
id |
number | Response only | Server-generated Java Long. |
code |
string | Yes | Unique among active rows and immutable. |
label |
string | Yes | Non-blank and mutable. |
description |
string or null |
No | Mutable. |
createdDate |
string | Response only | Server-owned Instant in ISO-8601 format. |
lastModifiedDate |
string | Response only | Server-owned Instant in ISO-8601 format. |
createdBy |
string | Response only | Authenticated username at creation. |
lastModifiedBy |
string | Response only | Authenticated username at the last persisted change. |
Task Fields¶
| Field | JSON type | Rules |
|---|---|---|
status |
string | TODO, IN_PROGRESS, DONE, or CANCELLED; default TODO. |
priority |
string | LOW, NORMAL, HIGH, or URGENT; default NORMAL. |
dueDate |
string or null |
Nullable calendar date in YYYY-MM-DD format, without a timezone. |
assignedTo |
string or null |
Nullable free-text assignee; not a user foreign key. |
tagIds |
number array | Existing tag IDs (Long[]); default []. |
nomenclatureId |
number or null |
Nullable existing nomenclature ID. |
Reusable Taxonomy Domains¶
Tag provides flat labels that can be attached to multiple tasks, such as
RELEASE or DOCUMENTATION. It has only the shared fields.
Nomenclature provides a reusable classification hierarchy, such as
Engineering → Release → Documentation. It has the shared fields plus
nullable parentId (a server-generated Long referencing another nomenclature).
null denotes a root. Self-parenting and longer cycles are rejected.
Task tag/nomenclature references and nomenclature parent references must exist.
Deleting a tag used by a task, a nomenclature used by a task, or a nomenclature
with children is rejected rather than silently removing references.
Invalid references and hierarchy cycles return 400 Bad Request; deleting a
referenced taxonomy entry returns 409 Conflict.
Task and taxonomy reads require ADMIN or USER; writes require ADMIN.
Endpoints¶
Authentication and Administration¶
| Method | Path | Description |
|---|---|---|
POST |
/api/v1/auth/login |
Exchange username/password for a JWT. |
GET |
/api/v1/auth/me |
Read the authenticated user. |
GET |
/api/v1/auth/users |
List users. Requires ADMIN. |
POST |
/api/v1/auth/users |
Create a user with a BCrypt-stored password. Requires ADMIN. |
GET |
/api/v1/auth/users/{id} |
Read a user. Requires ADMIN. |
PUT |
/api/v1/auth/users/{id} |
Update username, enabled flag, roles, and optionally password. Requires ADMIN. |
DELETE |
/api/v1/auth/users/{id} |
Delete a user. Requires ADMIN. |
POST |
/api/v1/auth/users/delete-selected |
Delete the users listed in {"ids":[...]}. Requires ADMIN. |
GET |
/api/v1/auth/roles |
List roles. Requires ADMIN. |
POST |
/api/v1/auth/roles |
Create a role. Requires ADMIN. |
GET |
/api/v1/auth/roles/{id} |
Read a role. Requires ADMIN. |
PUT |
/api/v1/auth/roles/{id} |
Update a role label. Requires ADMIN. |
DELETE |
/api/v1/auth/roles/{id} |
Delete a non-system role. Requires ADMIN. |
POST |
/api/v1/auth/roles/delete-selected |
Delete the roles listed in {"ids":[...]}; system roles are skipped. Requires ADMIN. |
The ANONYMOUS, ADMIN, and USER roles are seeded at first startup and
cannot be deleted. Bulk delete endpoints respond 200 OK with
{"deletedIds":[...],"skippedIds":[...]}; unknown IDs and protected rows are
reported as skipped. User responses never include passwords or password hashes.
User Settings¶
User settings are implemented in the fr.tiogars.chat.settings.user
package. The first setting is viewMode (light, dark, or system; default
system).
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/settings/user/me |
Read the authenticated user's settings. Requires USER or ADMIN. |
PUT |
/api/v1/settings/user/me |
Update the authenticated user's settings. Requires USER or ADMIN. |
GET |
/api/v1/settings/user/users/{userId} |
Read the settings of a user with the USER role. Requires ADMIN; returns 404 for other users. |
PUT |
/api/v1/settings/user/users/{userId} |
Update the settings of a user with the USER role. Requires ADMIN; returns 404 for other users. |
GET |
/api/v1/settings/user/anonymous |
Read the ANONYMOUS role settings. Public. |
PUT |
/api/v1/settings/user/anonymous |
Update the ANONYMOUS role settings. Requires ADMIN. |
Settings that were never saved are returned with default values; they are stored on first update and deleted with their user.
LM Studio Settings¶
The dedicated fr.tiogars.chat.domains.lmstudio domain stores one global
configuration in the lmstudio_settings table.
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/lmstudio/settings |
Read the configuration. Requires ADMIN; returns 404 until configured. |
PUT |
/api/v1/lmstudio/settings |
Create or replace the configuration. Requires ADMIN. |
Example request and response:
{
"baseUrl": "http://host.docker.internal:1234",
"model": "llama3.2",
"timeoutSeconds": 30
}
baseUrl must be an absolute HTTP(S) server URL without credentials, query
parameters or a fragment (maximum 2048 characters). Do not append
/v1/chat/completions; the client adds that path. model must be non-blank
and at most 255 characters; use the identifier loaded in LM Studio.
timeoutSeconds must be a strictly positive integer and applies to both
connection establishment and each HTTP request. Invalid settings return 400.
Settings survive API restarts and are read on each prompt call; changes take effect without restarting the API.
An optional token in the PUT body configures bearer authentication to LM Studio.
Send only the token value, without Bearer. Omitted or null preserves the
existing token; "" removes it. The token is limited to 4096 characters and must
use LM Studio token characters, including : (no whitespace or control characters). GET and PUT
responses never include token; tokenConfigured indicates whether it is set.
The token is stored in the database, not encrypted by the application; protect
database access and backups, and use HTTPS to protect it in transit.
The API starts without an LM Studio
configuration or a running LM Studio server. Until configured, prompt calls
return 503 Service Unavailable. The former lmstudio.base-url,
lmstudio.model, and lmstudio.timeout Spring properties are no longer used.
In a container, localhost refers to the API container, not the host running
LM Studio. Docker Desktop provides host.docker.internal; other deployments
must use a hostname/IP reachable from the API container. Enable LM Studio's
network server access and configure the host firewall accordingly.
Hibernate creates the new table with the current ddl-auto: update setting.
Tasks¶
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/task |
List all tasks, ordered by code. |
GET |
/api/v1/task/{id} |
Read one task by server ID. |
POST |
/api/v1/task |
Create a task. |
PUT |
/api/v1/task/{id} |
Update its mutable fields. |
DELETE |
/api/v1/task/{id} |
Archive one task without removing its database row. |
POST |
/api/v1/task/delete-selected |
Archive the tasks listed in {"ids":[...]}. Requires ADMIN. |
POST |
/api/v1/task/seed |
Upsert an array by code. |
POST |
/api/v1/task/import.json |
Import and upsert a JSON array by code. |
POST |
/api/v1/task/import.csv |
Import and upsert CSV rows by code. |
GET |
/api/v1/task/export.json |
Export all tasks as JSON. |
GET |
/api/v1/task/export.csv |
Export all tasks as CSV. |
GET |
/api/v1/task/{id}/print.pdf |
Print one active task as PDF. |
GET |
/api/v1/task/print.pdf |
Print all active tasks as PDF, ordered by code. |
POST |
/api/v1/task/print-selected.pdf |
Print the active tasks listed in {"ids":[...]} as PDF, ordered by code. |
Tags and Nomenclatures¶
Both taxonomy resources expose the following CRUD operations, where {domain}
is tag or nomenclature:
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/{domain} |
List entries. |
GET |
/api/v1/{domain}/{id} |
Read an entry. |
POST |
/api/v1/{domain} |
Create with code, label, optional description, and optional parentId for nomenclatures. |
PUT |
/api/v1/{domain}/{id} |
Update label, description, and optional parentId for nomenclatures; exclude code. |
DELETE |
/api/v1/{domain}/{id} |
Delete an unreferenced entry. |
Create taxonomy entries before tasks that reference them. For example, create a
tag with {"code":"RELEASE","label":"Release","description":null} and a root
nomenclature with
{"code":"ENGINEERING","label":"Engineering","description":null,"parentId":null}.
Use the returned IDs, not codes, in task references and child parentId values.
PDF Printing¶
PDF printing uses Apache PDFBox 3.0.7 and three dedicated services for one, all,
and selected tasks. All three endpoints require the same JWT
authentication and ADMIN or USER role as reading tasks and return
application/pdf, inline Content-Disposition, and Cache-Control: no-store.
Each record starts on a new A4 page and includes its ID, code, label,
description, and audit fields. Long fields wrap and continue onto additional
numbered pages. The embedded Liberation Sans font supplied by PDFBox supports
accented Latin, Greek, and Cyrillic text; unsupported characters return
422 Unprocessable Content instead of silently changing the content. Printing
an empty collection returns a PDF stating that there are no tasks.
The selected request accepts 1 to 1000 positive IDs. Duplicate IDs print only
once. Invalid selections return 400 Bad Request; an unknown or archived ID
returns 404 Not Found for the entire request, so a PDF never silently omits
selected records. Archived records are excluded from all PDF queries.
In the React backend console, Print all prints every active record, independently of grid pagination or filtering. Print selected prints only the checkbox-selected grid rows, including selections across pages, and is disabled when nothing is selected. Print on the detail page prints the current saved record. Each action opens the generated PDF in a new browser tab; use the PDF viewer's native Print control to choose a printer. Popups must be allowed for the site. Failed requests close the blank viewer and display an error in the console.
The React client's print(id), printAll(), and printSelected(ids) methods
return Promise<Blob>. Binary requests use the configured API URL, fetcher, and
token provider directly, outside the JSON-oriented RTK Query cache, avoiding
non-serializable PDF objects in Redux state.
Create¶
POST /api/v1/task accepts only business fields:
{
"code": "RELEASE-001",
"label": "Prepare release",
"description": "Review the release checklist",
"status": "TODO",
"priority": "HIGH",
"dueDate": "2026-11-01",
"assignedTo": "alice",
"tagIds": [],
"nomenclatureId": null
}
The response is 201 Created, includes the complete resource, and sets
Location to /api/v1/task/{id}. A duplicate code returns
409 Conflict. Blank required fields return 400 Bad Request.
Read¶
GET /api/v1/task returns a JSON array.
GET /api/v1/task/{id} returns one task or 404 Not Found.
Update¶
PUT /api/v1/task/{id} accepts the mutable fields only; code is excluded:
{
"label": "Prepare release",
"description": null,
"status": "IN_PROGRESS",
"priority": "HIGH",
"dueDate": "2026-11-01",
"assignedTo": "alice",
"tagIds": [],
"nomenclatureId": null
}
The server preserves id, code, and createdDate, and replaces
lastModifiedDate. The response is 200 OK, or 404 Not Found for an unknown
ID.
Delete¶
DELETE /api/v1/task/{id} returns 204 No Content, or
404 Not Found for an unknown or already archived ID.
POST /api/v1/task/delete-selected archives several tasks in one
transaction. The body is {"ids":[1,2,3]} and the response is
{"deletedIds":[1,2],"skippedIds":[3]}, where skipped IDs were unknown or
already archived. The admin console uses it for the grid's "Delete selected"
action.
Deletion sets deleted_date and deleted_by; the original ID, code, business
fields, and creation metadata remain in PostgreSQL. Archived rows are excluded
from all normal JPA queries, including read, update, list, export, duplicate
checks, and seed/import lookups. They cannot be updated or restored through the
API.
After deletion, creating the same code produces a new row with a new ID. Seed/import also creates a new row rather than reviving the archived row. Multiple archived rows may share a code, but a PostgreSQL partial unique index permits at most one active row per code. Optimistic versioning prevents stale writers from overwriting a deletion or another update.
Concurrent writes that lose an optimistic-lock race, or violate active-code
uniqueness, return 409 Conflict; other database integrity errors are not
treated as duplicate-code conflicts. Refresh the resource before retrying.
Persistence Auditing and Required Migration¶
Tasks, tags, and nomenclatures have server-owned auditing. Task deletion archives the task; taxonomy deletion is subject to reference checks. Users, roles, and user settings retain their existing behavior. Spring Data JPA supplies creation and modification timestamps, truncated to PostgreSQL microsecond precision, and records the authenticated username:
| Database column | Meaning |
|---|---|
created_by |
Username at creation; never changed. |
last_modified_by |
Username at the last persisted change, including deletion. |
deleted_by |
Username that archived the row, or NULL while active. |
deleted_date |
Archival timestamp, or NULL while active. |
version |
Optimistic concurrency token managed by JPA. |
Actors are username snapshots, not foreign keys: changing or deleting a user
does not erase the recorded name. Writes without an authenticated security
context fail; scheduled jobs must establish an explicit service identity. JSON
responses (including JSON exports) expose createdBy and lastModifiedBy as
read-only fields, displayed alongside their timestamps in the backend console
detail view. Historical actors backfilled by the migration appear as unknown.
Deletion metadata and the optimistic-lock version remain persistence-only; the
CSV fields are described below. Spring Data auditing records the creator and
most recent editor, not a full revision history.
Before deploying this API version, stop API writers, back up the database, and run the manual PostgreSQL task-domain migration. Run it for both existing and new databases, using the same schema/search path as the API. For example, with PostgreSQL connection variables configured:
psql -v ON_ERROR_STOP=1 -f java\api\src\main\resources\db\manual\task-domains.sql
The task-domain migration defines the task and taxonomy persistence schema.
Hibernate ddl-auto: update is not a replacement for this migration and does
not remove obsolete tables or migrate legacy business data automatically.
Review the script against a database backup before upgrading.
This script replaces the former auditing migration for the
legacy domain_templates schema. Archived task history is persistence-only and is not exposed by normal
API endpoints.
The PostgreSQL lifecycle tests require Docker and run with the normal API test suite:
mvn -B -f java\pom.xml -pl api test
Seed and Import¶
Seed and both import formats use upsert semantics keyed by code: a missing
code creates a task and an existing code updates all mutable task fields.
Client-supplied id, createdDate, lastModifiedDate, createdBy, and
lastModifiedBy values are ignored. The server keeps ownership of identifiers,
timestamps, and audit actors.
POST /api/v1/task/seed and POST /api/v1/task/import.json
accept an array. A minimal document is:
[
{
"code": "RELEASE-001",
"label": "Prepare release",
"description": null
}
]
Both return 201 Created with the stored resources.
Omitted workflow fields use the task defaults; optional date, assignee, and
nomenclature values may be null. Imports may include all mutable fields,
including tagIds; taxonomy references must already exist in the same database.
Exported numeric taxonomy IDs are not portable to another database unless the
same referenced entries exist there with matching IDs.
Import and Export Formats¶
JSON export returns the complete resource schema. The same exported JSON can be imported: server-owned fields are accepted only as transport data and ignored during the upsert.
[
{
"id": 42,
"code": "RELEASE-001",
"label": "Prepare release",
"description": "Review the release checklist",
"status": "TODO",
"priority": "HIGH",
"dueDate": "2026-11-01",
"assignedTo": "alice",
"tagIds": [],
"nomenclatureId": null,
"createdDate": "2026-08-30T17:00:00Z",
"lastModifiedDate": "2026-08-30T17:00:00Z",
"createdBy": "admin",
"lastModifiedBy": "admin"
}
]
CSV import and export use this header:
id,code,label,description,createdDate,lastModifiedDate,status,priority,dueDate,assignedTo,tagIds,nomenclatureId
The 12-column header and column order above round-trip all task business fields.
tagIds is a semicolon-separated list of positive IDs (for example 3;7);
an empty cell means []. Empty description, dueDate, assignedTo, and
nomenclatureId cells become null. Blank status and priority use TODO and
NORMAL. Date values use YYYY-MM-DD; referenced IDs must already exist.
On import, id, createdDate, and lastModifiedDate are ignored. Audit actors
are not included in CSV.
id,code,label,description,createdDate,lastModifiedDate,status,priority,dueDate,assignedTo,tagIds,nomenclatureId
42,RELEASE-001,Prepare release,Review the release checklist,2026-08-30T17:00:00Z,2026-08-30T17:00:00Z,TODO,HIGH,2026-11-01,alice,,
For backward-compatible import, the exact legacy header
id,code,label,description,createdDate,lastModifiedDate is also accepted. Its
rows use the new task-field defaults; export always writes the extended header.
Response¶
{
"id": 42,
"code": "RELEASE-001",
"label": "Prepare release",
"description": "Review the release checklist",
"status": "TODO",
"priority": "HIGH",
"dueDate": "2026-11-01",
"assignedTo": "alice",
"tagIds": [],
"nomenclatureId": null,
"createdDate": "2026-08-30T17:00:00Z",
"lastModifiedDate": "2026-08-30T17:05:00Z",
"createdBy": "admin",
"lastModifiedBy": "editor"
}
Clients¶
The java-client, react-client, and dart-client modules provide typed Java,
TypeScript, and Dart access to CRUD, seed, import, and export operations.
Construct each client with the service origin; the client appends
/api/v1/task. Taxonomy clients use /api/v1/tag and
/api/v1/nomenclature. Application package names and artifact coordinates remain
unchanged.
The react-client also generates RTK Query endpoints and exports an
AuthClient for login, current-user lookup, and user and role administration
under /api/v1/auth, and a UserSettingsClient for user settings under
/api/v1/settings/user.