Base URL defaults to http://localhost:8080/api in development and production (proxied through nginx). All authenticated requests rely on an HttpOnly session cookie containing a JWT signed with HS256.
- Role: Public
- Body:
{ "username": "string", "password": "string" } - Responses:
200 OK– setssessioncookie and returns current user metadata.{ "id": "uuid", "username": "admin", "role": "ADMIN" }401 Unauthorized– invalid credentials.429 Too Many Requests– login rate limiter triggered (5 attempts/minute per IP).
- Role: Authenticated (any role)
- Effect: Clears
sessioncookie. - Responses:
204 No Content.
- Role: Authenticated (any role)
- Responses:
200 OK– returns the decoded JWT payload (id,username,role).401 Unauthorized– missing/invalid cookie.
- Role: Public
- Response:
{ "status": "ok", "time": "2024-01-01T12:00:00.000Z" }
All item endpoints require authentication. Non-admin users can read all items but may only mutate items where ownerId matches their user ID. Admins can manage every item and can set the owner_id explicitly when creating.
- Role: Authenticated
- Response: Array of items within the requested month.
[ { "id": "uuid", "date": "2024-10-07T00:00:00.000Z", "type": "EVENT", "title": "Soccer practice", "body": "Bring cleats", "ownerId": "uuid", "owner": { "id": "uuid", "username": "alex" }, "createdAt": "2024-09-01T18:00:00.000Z", "updatedAt": "2024-09-01T18:00:00.000Z" } ] - Errors:
400 Bad Requestifmonthis missing or malformed.
- Role: Authenticated
- Params:
dateinYYYY-MM-DDformat. - Response: Array of items for the specific day.
- Errors:
400 Bad Request(invalid date).
- Role: Authenticated
- Body:
{ "date": "2024-10-07", "type": "EVENT", "title": "Dentist", "body": "9am check-up", "owner_id": "uuid" // optional, admin only } - Responses:
200 OKwith created item JSON.
- Role: Item owner or admin
- Body: any subset of
{ "title", "body", "type" }. - Responses:
200 OK– updated item.404 Not Found– item does not exist.403 Forbidden– non-owner attempting to modify another user's item.
- Role: Item owner or admin
- Responses:
204 No Content– successfully deleted.404 Not Found– missing item.403 Forbidden– non-owner delete attempt.
- Role: Authenticated
- Response:
{ "days": { "2024-10-07": { "owner": "Parent A", "label": "Mom", "color": "indigo", "blockId": "uuid" } }, "blocks": [ { "id": "uuid", "startDate": "2024-10-07", "endDate": "2024-10-13", "owner": "Parent A", "label": "Mom", "color": "indigo", "createdAt": "2024-09-28T15:30:00.000Z", "updatedAt": "2024-09-28T15:30:00.000Z" } ] }
- Role: Admin only (
role === "ADMIN"). - Endpoints:
GET /schedule/blocks?start=YYYY-MM-DD&end=YYYY-MM-DD- Optional
start/endfilters (inclusive). Returns sorted blocks.
- Optional
POST /schedule/blocks{ "startDate": "2024-10-07", "endDate": "2024-10-13", "owner": "Parent A", "label": "Mom", "color": "indigo" }PUT /schedule/blocks/:id– update subset of fields;label/colorcan be set tonullto remove.DELETE /schedule/blocks/:id
- Errors:
400 Bad Request(invalid dates or empty payload),403 Forbidden,404 Not Foundfor missing block.
- Role: Admin only
- Endpoints:
GET /schedule/templates/cycle– returns the active template ornull.PUT /schedule/templates/cycle{ "name": "Default 2-2-5-5", "days": [ { "dayIndex": 0, "owner": "Parent A", "label": "Mom", "color": "indigo" }, { "dayIndex": 1, "owner": "Parent A" }, { "dayIndex": 27, "owner": "Parent B", "label": "Dad" } ] }daysmust include between 1 and 42 entries covering contiguous indices starting at0(e.g.,0-41for a six-week cycle).
POST /schedule/templates/cycle/apply{ "anchorDate": "2024-10-07", "cycles": 6, "replaceExisting": true }- Generates schedule blocks starting at
anchorDateforcycles * template_lengthdays (default 6 cycles) and optionally deletes overlapping future blocks.
- Generates schedule blocks starting at
- Responses: Summary payload including number of blocks created and range applied.
All routes below are prefixed with /admin because of router registration (/api/admin/...). Only admins may access these endpoints.
- Returns list of users with
id,username,role,createdAt.
- Body:
{ "username": "casey", "password": "changeme", "role": "USER" } - Response:
200 OKwith newly created user metadata.
- Body:
{ "password": "newpass", // optional "role": "ADMIN" // optional } - At least one field is required; returns updated user.
- Response:
204 No Content.
Errors are returned as JSON objects of the form:
{ "error": "description" }Common status codes:
| Status | Meaning |
|---|---|
400 |
Validation error (missing parameters, bad dates). |
401 |
Missing or invalid authentication cookie. |
403 |
Authenticated but lacks required admin role. |
404 |
Entity not found. |
409 |
Reserved for conflict scenarios (not currently used). |
429 |
Rate limited (/auth/login). |
500 |
Unexpected server error. |
| Role | Permissions |
|---|---|
USER |
Read/write own items, read shared schedule, read list of items. |
ADMIN |
Full access: manage users, manage schedule blocks/templates, create items on behalf of others, view everything. |
# Login as admin and store cookie
curl -c cookies.txt -H 'Content-Type: application/json' \
-X POST http://localhost/api/auth/login \
-d '{"username":"admin","password":"changeme"}'
# Create a schedule block (admin only)
curl -b cookies.txt -H 'Content-Type: application/json' \
-X POST http://localhost/api/schedule/blocks \
-d '{"startDate":"2024-10-07","endDate":"2024-10-13","owner":"Parent A","label":"Mom","color":"indigo"}'
# List users (admin only)
curl -b cookies.txt http://localhost/api/admin/users