diff --git a/.github/assets/gifs/DockStatAPI-startup.gif b/.github/assets/gifs/DockStatAPI-startup.gif new file mode 100644 index 00000000..7134ad69 Binary files /dev/null and b/.github/assets/gifs/DockStatAPI-startup.gif differ diff --git a/.github/assets/logos/square.png b/.github/assets/logos/square.png new file mode 100644 index 00000000..c4d85313 Binary files /dev/null and b/.github/assets/logos/square.png differ diff --git a/apps/api/.env.example b/apps/api/.env.example index 839db98c..79097898 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -3,3 +3,4 @@ DOCKSTAT_LOGGER_ONLY_SHOW="" DOCKSTAT_LOGGER_IGNORE_MESSAGES="Logger Status: active" DOCKSTAT_LOGGER_FULL_FILE_PATH=false DOCKSTAT_API_PORT="3030" +DOCKSTAT_LOGGER_LEVEL="INFO" diff --git a/apps/api/README.md b/apps/api/README.md index c0c460f5..56ccc83e 100644 --- a/apps/api/README.md +++ b/apps/api/README.md @@ -7,6 +7,8 @@ updatedAt: 2026-01-01T15:02:00.500Z urlId: gVYlljv3Fs --- +![DockStatAPI Animation](https://raw.githubusercontent.com/Its4Nik/DockStat/refs/heads/DockStatAPI-readme-update/.github/assets/gifs/DockStatAPI-startup.gif) + > The DockStatAPI is implemented with Elysia and exposed under the prefix `/api/v2`. The canonical route definitions are in `apps/api/src/routes/` with schemas in `apps/api/src/models/`. ## Base URL diff --git a/apps/dockstat/src/lib/actions/README.md b/apps/dockstat/src/lib/actions/README.md index d3f870f8..345f6c8d 100644 --- a/apps/dockstat/src/lib/actions/README.md +++ b/apps/dockstat/src/lib/actions/README.md @@ -1,9 +1,9 @@ --- id: 57802308-6a42-4d47-82b6-bc553ae10e9c -title: "Frontend: actions" +title: "Frontend: Actions" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: a81b5d89-a300-47ac-8ffa-a3b851645978 -updatedAt: 2026-01-01T14:27:30.440Z +updatedAt: 2026-01-01T20:40:03.579Z urlId: 0tWEK43tNb --- @@ -34,9 +34,9 @@ export async function updateProfile(input: UpdateProfileInput) { }) if (error) { - throw new Error(extractEdenError({ data, error })) + throw new Error(String(error.value)) } - + return data } ``` @@ -90,4 +90,4 @@ export function ProfileForm() { * Always `throw` on API errors (React Query will surface it in `mutation.error`) * Keep **UI concerns out** of actions (no toasts, no routing, no cache invalidation here) * Keep input types close to the action -* Return only what the caller needs (don't over-return) +* Return only what the caller needs (don't over-return) \ No newline at end of file diff --git a/apps/dockstat/src/lib/queries/README.md b/apps/dockstat/src/lib/queries/README.md index 6eaba6ee..e502409e 100644 --- a/apps/dockstat/src/lib/queries/README.md +++ b/apps/dockstat/src/lib/queries/README.md @@ -1,9 +1,9 @@ --- id: da3758e1-2d46-4dd5-85c5-eb9d19ee2054 -title: "Frontend: queries" +title: "Frontend: Queries" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: a81b5d89-a300-47ac-8ffa-a3b851645978 -updatedAt: 2026-01-01T15:02:36.975Z +updatedAt: 2026-01-01T20:40:14.966Z urlId: wadWIa69wa --- @@ -68,4 +68,4 @@ export function Status() { * Always `throw` on API errors (don't return `{ error }`) * Return the smallest useful `data` shape * No UI logic here (no toasts, no redirects) -* Keep `queryKey`s in the component (or optionally export helpers if you standardize keys later) +* Keep `queryKey`s in the component (or optionally export helpers if you standardize keys later) \ No newline at end of file diff --git a/apps/dockstat/src/lib/websocketEffects/README.md b/apps/dockstat/src/lib/websocketEffects/README.md index ad1e8697..83f3ce97 100644 --- a/apps/dockstat/src/lib/websocketEffects/README.md +++ b/apps/dockstat/src/lib/websocketEffects/README.md @@ -3,7 +3,7 @@ id: aab7cefb-b84b-4be9-8840-a873b69c6850 title: "Frontend: Websockets" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: a81b5d89-a300-47ac-8ffa-a3b851645978 -updatedAt: 2026-01-01T14:28:14.767Z +updatedAt: 2026-01-01T20:39:33.079Z urlId: vcQwuQaPn0 --- @@ -78,4 +78,4 @@ new Elysia() * One effect = one socket. * Always return a cleanup function so the socket is closed on unmount. -* Keep the effect **pure**: no UI, no toasts, only state synchronization. +* Keep the effect **pure**: no UI, no toasts, only state synchronization. \ No newline at end of file diff --git a/apps/docs/dockstat/api-reference/README.md b/apps/docs/dockstat/api-reference/README.md index cbdd1ce4..841b0970 100644 --- a/apps/docs/dockstat/api-reference/README.md +++ b/apps/docs/dockstat/api-reference/README.md @@ -83,12 +83,12 @@ Returns the overall DockerClientManager status, including worker pool metrics. ### Hosts `/docker/hosts` -| Method | Path | Description | -| ------ | ------------------ | --------------------------------- | -| GET | `/hosts/` | List all hosts | -| GET | `/hosts/:clientId` | Get metrics for a specific client | -| POST | `/hosts/add` | Add a new host | -| POST | `/hosts/update` | Update an existing host | +| Method | Path | Description | +|----|----|----| +| GET | `/hosts/` | List all hosts | +| GET | `/hosts/:clientId` | Get metrics for a specific client | +| POST | `/hosts/add` | Add a new host | +| POST | `/hosts/update` | Update an existing host | **POST** `**/hosts/add**` **body:** @@ -119,13 +119,13 @@ Returns the overall DockerClientManager status, including worker pool metrics. ### Client `/docker/client` -| Method | Path | Description | -| ------ | ------------------------------ | ----------------------------- | -| POST | `/client/register` | Register a new Docker client | -| DELETE | `/client/delete` | Remove a client | -| GET | `/client/all/:stored` | List all clients | -| POST | `/client/monitoring/:id/start` | Start monitoring for a client | -| POST | `/client/monitoring/:id/stop` | Stop monitoring for a client | +| Method | Path | Description | +|----|----|----| +| POST | `/client/register` | Register a new Docker client | +| DELETE | `/client/delete` | Remove a client | +| GET | `/client/all/:stored` | List all clients | +| POST | `/client/monitoring/:id/start` | Start monitoring for a client | +| POST | `/client/monitoring/:id/stop` | Stop monitoring for a client | **POST** `**/client/register**` **body:** @@ -148,18 +148,18 @@ Returns the overall DockerClientManager status, including worker pool metrics. ### Containers `/docker/containers` -| Method | Path | Description | -| ------ | --------------------------- | ------------------------------- | -| GET | `/containers/all/:clientId` | Get all containers for a client | +| Method | Path | Description | +|----|----|----| +| GET | `/containers/all/:clientId` | Get all containers for a client | **Response:** Array of container objects with stats. ### Manager `/docker/manager` -| Method | Path | Description | -| ------ | --------------------------- | --------------------------------- | -| GET | `/manager/pool-stats` | Get worker pool statistics | -| POST | `/manager/init-all-clients` | Initialize all registered clients | +| Method | Path | Description | +|----|----|----| +| GET | `/manager/pool-stats` | Get worker pool statistics | +| POST | `/manager/init-all-clients` | Initialize all registered clients | ## Metrics Routes `/api/v2/metrics` @@ -169,10 +169,10 @@ Returns Prometheus-formatted metrics for the API and database. **Response 200:** Prometheus text format with: -- HTTP request counters -- Request duration histograms -- Database size and table metrics -- Memory usage statistics +* HTTP request counters +* Request duration histograms +* Database size and table metrics +* Memory usage statistics ## Plugin Routes `/api/v2/plugins` @@ -199,16 +199,16 @@ sequenceDiagram API-->>Client: 200 OK ``` -| Method | Path | Description | -| ------ | ----------------------- | ---------------------------------------- | -| GET | `/plugins/all` | List all installed plugins | -| GET | `/plugins/hooks` | Get available hook handlers | -| GET | `/plugins/status` | Get plugin system status | -| POST | `/plugins/install` | Install a plugin | -| POST | `/plugins/activate` | Activate plugins by ID | -| POST | `/plugins/delete` | Delete a plugin | -| GET | `/plugins/routes` | List plugin-provided routes | -| ALL | `/plugins/:id/routes/*` | Proxy requests to plugin Elysia instance | +| Method | Path | Description | +|----|----|----| +| GET | `/plugins/all` | List all installed plugins | +| GET | `/plugins/hooks` | Get available hook handlers | +| GET | `/plugins/status` | Get plugin system status | +| POST | `/plugins/install` | Install a plugin | +| POST | `/plugins/activate` | Activate plugins by ID | +| POST | `/plugins/delete` | Delete a plugin | +| GET | `/plugins/routes` | List plugin-provided routes | +| ALL | `/plugins/:id/routes/*` | Proxy requests to plugin Elysia instance | **POST** `**/plugins/install**` **body:** @@ -242,10 +242,10 @@ sequenceDiagram ## Database Routes `/api/v2/db` -| Method | Path | Description | -| ------ | ------------ | ------------------------- | -| GET | `/db/config` | Get current configuration | -| POST | `/db/config` | Update configuration | +| Method | Path | Description | +|----|----|----| +| GET | `/db/config` | Get current configuration | +| POST | `/db/config` | Update configuration | **POST** `**/db/config**` **body:** Configuration object matching `DockStatConfigTable` schema from `@dockstat/typings`. @@ -281,3 +281,18 @@ All routes use a global error handler that returns structured errors: ## Authentication The current API implementation does not enforce authentication at the route level. For production deployments, add an authentication layer via reverse proxy or Elysia middleware. + +## Source Files + +| File | Description | +|----|----| +| `apps/api/src/index.ts` | API entry point | +| `apps/api/src/routes/docker/index.ts` | Docker route aggregator | +| `apps/api/src/routes/docker/hosts.ts` | Host management routes | +| `apps/api/src/routes/docker/client.ts` | Client management routes | +| `apps/api/src/routes/docker/container.ts` | Container routes | +| `apps/api/src/routes/docker/manager.ts` | Manager routes | +| `apps/api/src/routes/plugins/index.ts` | Plugin routes | +| `apps/api/src/routes/db.ts` | Database configuration routes | +| `apps/api/src/routes/metrics/prometheus.ts` | Metrics endpoint | +| `apps/api/src/models/*.ts` | Request/response schemas | \ No newline at end of file diff --git a/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md b/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md index 821289b7..281803de 100644 --- a/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md +++ b/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md @@ -15,29 +15,30 @@ This document describes the frontend-related plugin endpoints exposed by the Doc Base URL (development) -- [http://localhost:3000/api/v2/plugins/frontend](http://localhost:3000/api/v2/plugins/frontend) +* [http://localhost:3000/api/v2/plugins/frontend](http://localhost:9876/api/v2/plugins/frontend) Overview -- These endpoints let clients inspect plugin-provided frontend routes, templates and fragments, and execute route-level "loaders" and "actions" provided by plugins. -- The endpoints are implemented by the `PluginHandler` module which exposes functions such as `getAllFrontendRoutes`, `getFrontendNavigationItems`, `executeRouteLoaders`, `executeAction`, etc. The route definitions and handler wiring are in the implementation referenced above. +* These endpoints let clients inspect plugin-provided frontend routes, templates and fragments, and execute route-level "loaders" and "actions" provided by plugins. +* The endpoints are implemented by the `PluginHandler` module which exposes functions such as `getAllFrontendRoutes`, `getFrontendNavigationItems`, `executeRouteLoaders`, `executeAction`, etc. The route definitions and handler wiring are in the implementation referenced above. Important note about `pluginId` -- The routes accept `:pluginId` as a path parameter. Internally the code converts it to a Number (e.g. `Number(params.pluginId)`), so pass numeric plugin IDs (or numeric strings) when calling these endpoints. +* The routes accept `:pluginId` as a path parameter. Internally the code converts it to a Number (e.g. `Number(params.pluginId)`), so pass numeric plugin IDs (or numeric strings) when calling these endpoints. Common response shape -- Success responses generally return JSON objects with the requested data (arrays / objects). -- When a referenced resource (route, loader, action) can't be found, the endpoints return an error object with contextual fields (e.g. `error`, `pluginId`, `routePath`, `loaderId` / `actionId`). +* Success responses generally return JSON objects with the requested data (arrays / objects). +* When a referenced resource (route, loader, action) can't be found, the endpoints return an error object with contextual fields (e.g. `error`, `pluginId`, `routePath`, `loaderId` / `actionId`). Endpoints + 1. GET /routes -- Path: `/plugins/frontend/routes` -- Description: Return all frontend routes provided by all loaded plugins. -- Response: Array of route definitions. Each route typically contains metadata such as `pluginId`, `path`, `meta` (title, icon, showInNav), and route config. +* Path: `/plugins/frontend/routes` +* Description: Return all frontend routes provided by all loaded plugins. +* Response: Array of route definitions. Each route typically contains metadata such as `pluginId`, `path`, `meta` (title, icon, showInNav), and route config. Example: @@ -52,71 +53,54 @@ Example: ] ``` + 2. GET /routes/by-plugin -- Path: `/plugins/frontend/routes/by-plugin` -- Description: Returns frontend routes grouped by plugin. -- Response: Object keyed by `pluginId` with arrays of route objects. +* Path: `/plugins/frontend/routes/by-plugin` +* Description: Returns frontend routes grouped by plugin. +* Response: Object keyed by `pluginId` with arrays of route objects. + 3. GET /navigation -- Path: `/plugins/frontend/navigation` -- Description: Returns navigation items for plugins that expose frontend routes (useful for building a combined navigation). -- Response: Array of navigation entries (title, path, icon, pluginId, order, etc). +* Path: `/plugins/frontend/navigation` +* Description: Returns navigation items for plugins that expose frontend routes (useful for building a combined navigation). +* Response: Array of navigation entries (title, path, icon, pluginId, order, etc). + 4. GET /summary -- Path: `/plugins/frontend/summary` -- Description: Returns a compact summary of frontend configurations across plugins (counts, which plugins expose routes/templates/fragments, etc). -- Response: Summary object. +* Path: `/plugins/frontend/summary` +* Description: Returns a compact summary of frontend configurations across plugins (counts, which plugins expose routes/templates/fragments, etc). +* Response: Summary object. + 5. POST /:pluginId/template -- Path: `/plugins/frontend/:pluginId/template` -- Description: Get the template for a specific plugin frontend route, along with fragments, loader/action definitions, and initial data produced by executing route loaders. -- Params: - - Path param: `pluginId` (string numeric) -- Body: - - `{ "path": "/route-path" }` — string path to the route (the server will normalize to `/${body.path || ""}`) -- Response: - - On success: +* Path: `/plugins/frontend/:pluginId/template` +* Description: Get the template for a specific plugin frontend route, along with fragments, loader/action definitions, and initial data produced by executing route loaders. +* Params: + * Path param: `pluginId` (string numeric) +* Body: + * `{ "path": "/route-path" }` — string path to the route (the server will normalize to `/${body.path || ""}`) +* Response: + * On success: ```json { - "route": { - "path": "/my-plugin", - "meta": { "title": "My Plugin" }, - "config": { - /* route config */ - } - }, - "template": { - /* template object (builder / parsed JSON/YAML) */ - }, - "fragments": { - /* shared fragments keyed by fragment id */ - }, - "loaders": [ - /* loader definitions for this route */ - ], - "actions": [ - /* action definitions for this route */ - ], + "route": { "path": "/my-plugin", "meta": { "title": "My Plugin" }, "config": { /* route config */ } }, + "template": { /* template object (builder / parsed JSON/YAML) */ }, + "fragments": { /* shared fragments keyed by fragment id */ }, + "loaders": [ /* loader definitions for this route */ ], + "actions": [ /* action definitions for this route */ ], "initialData": { - "loaderResults": [ - /* results for each loader executed */ - ], - "state": { - /* merged state as returned from loaders */ - }, - "data": { - /* additional data returned by loaders */ - } + "loaderResults": [ /* results for each loader executed */ ], + "state": { /* merged state as returned from loaders */ }, + "data": { /* additional data returned by loaders */ } } } ``` - - - If route not found: + * If route not found: ```json { @@ -134,44 +118,48 @@ curl -X POST "http://localhost:9876/api/v2/plugins/frontend/1/template" \ -d '{"path": "my-plugin"}' ``` + 6. GET /:pluginId/has-routes -- Path: `/plugins/frontend/:pluginId/has-routes` -- Description: Check whether the plugin exposes any frontend routes. -- Response: - - `{ "pluginId": 1, "hasFrontendRoutes": true }` +* Path: `/plugins/frontend/:pluginId/has-routes` +* Description: Check whether the plugin exposes any frontend routes. +* Response: + * `{ "pluginId": 1, "hasFrontendRoutes": true }` Frontend Loaders endpoints -- Loaders are route-level functions provided by plugins that produce initial data/state for a frontend route. +* Loaders are route-level functions provided by plugins that produce initial data/state for a frontend route. + 7. GET /:pluginId/loaders -- Path: `/plugins/frontend/:pluginId/loaders` -- Query: - - `path` (optional) — route path for which to list loaders -- Response: - - `{ "pluginId": 1, "routePath": "/my-plugin", "loaders": [ /* loader defs */ ] }` +* Path: `/plugins/frontend/:pluginId/loaders` +* Query: + * `path` (optional) — route path for which to list loaders +* Response: + * `{ "pluginId": 1, "routePath": "/my-plugin", "loaders": [ /* loader defs */ ] }` + 8. POST /:pluginId/loaders/execute -- Path: `/plugins/frontend/:pluginId/loaders/execute` -- Body: - - `{ "path": "/route", "state": { /* optional state to pass to loaders */ } }` -- Description: Execute all loaders for the given route. Returns combined loader results, state and any loader-specific data. -- Response: - - `{ "pluginId": 1, "routePath": "/my-plugin", "results": [ ... ], "state": { ... }, "data": { ... } }` +* Path: `/plugins/frontend/:pluginId/loaders/execute` +* Body: + * `{ "path": "/route", "state": { /* optional state to pass to loaders */ } }` +* Description: Execute all loaders for the given route. Returns combined loader results, state and any loader-specific data. +* Response: + * `{ "pluginId": 1, "routePath": "/my-plugin", "results": [ ... ], "state": { ... }, "data": { ... } }` + 9. POST /:pluginId/loaders/:loaderId/execute -- Path: `/plugins/frontend/:pluginId/loaders/:loaderId/execute` -- Body: - - `{ "path": "/route", "state": { /* optional */ } }` -- Description: Execute a specific loader by its ID. -- Response: - - On success: - - `{ "pluginId": 1, "routePath": "/my-plugin", "loaderId": "loader-1", "result": { /* loader output */ } }` - - If loader not found: +* Path: `/plugins/frontend/:pluginId/loaders/:loaderId/execute` +* Body: + * `{ "path": "/route", "state": { /* optional */ } }` +* Description: Execute a specific loader by its ID. +* Response: + * On success: + * `{ "pluginId": 1, "routePath": "/my-plugin", "loaderId": "loader-1", "result": { /* loader output */ } }` + * If loader not found: ```json { @@ -184,85 +172,89 @@ Frontend Loaders endpoints Frontend Actions endpoints -- Actions are operations bound to UI events (e.g. button clicks) implemented by plugins. +* Actions are operations bound to UI events (e.g. button clicks) implemented by plugins. + 10. GET /:pluginId/actions -- Path: `/plugins/frontend/:pluginId/actions` -- Query: - - `path` (optional) — route path -- Description: List actions available for a plugin route. -- Response: - - `{ "pluginId": 1, "routePath": "/my-plugin", "actions": [ /* action defs */ ] }` +* Path: `/plugins/frontend/:pluginId/actions` +* Query: + * `path` (optional) — route path +* Description: List actions available for a plugin route. +* Response: + * `{ "pluginId": 1, "routePath": "/my-plugin", "actions": [ /* action defs */ ] }` + 11. POST /:pluginId/actions/:actionId/execute -- Path: `/plugins/frontend/:pluginId/actions/:actionId/execute` -- Body: - - `{ "path": "/route", "state": { /* optional state */ }, "payload": /* optional arbitrary payload */ }` -- Description: Execute a single frontend action. Useful to drive state changes or call plugin-provided handlers from the API (or test them). -- Response: - - On success: - - `{ "pluginId": 1, "routePath": "/my-plugin", "actionId": "act-1", "result": { /* action result */ } }` - - If action not found: - - Returns an error object similar to the loader not found case. +* Path: `/plugins/frontend/:pluginId/actions/:actionId/execute` +* Body: + * `{ "path": "/route", "state": { /* optional state */ }, "payload": /* optional arbitrary payload */ }` +* Description: Execute a single frontend action. Useful to drive state changes or call plugin-provided handlers from the API (or test them). +* Response: + * On success: + * `{ "pluginId": 1, "routePath": "/my-plugin", "actionId": "act-1", "result": { /* action result */ } }` + * If action not found: + * Returns an error object similar to the loader not found case. + 12. GET /:pluginId/actions/:actionId -- Path: `/plugins/frontend/:pluginId/actions/:actionId` -- Query: - - `path` (optional) — route path -- Description: Get a specific action's definition (id, type, expected payload, side effects, etc). -- Response: - - On success: - - `{ "pluginId": 1, "routePath": "/my-plugin", "action": { /* action definition */ } }` - - If not found: - - `{ "error": "Action not found", "pluginId": 1, "routePath": "/my-plugin", "actionId": "unknown" }` +* Path: `/plugins/frontend/:pluginId/actions/:actionId` +* Query: + * `path` (optional) — route path +* Description: Get a specific action's definition (id, type, expected payload, side effects, etc). +* Response: + * On success: + * `{ "pluginId": 1, "routePath": "/my-plugin", "action": { /* action definition */ } }` + * If not found: + * `{ "error": "Action not found", "pluginId": 1, "routePath": "/my-plugin", "actionId": "unknown" }` Schemas and types -- Request validation is provided using `t.Object(...)` schemas in the route definitions. Example validators: - - `params: t.Object({ pluginId: t.String() })` (plugin id is validated as a string param) - - `body: t.Object({ path: t.String(), state: t.Optional(t.Record(t.String(), t.Unknown())) })` - - `query: t.Object({ path: t.Optional(t.String()) })` +* Request validation is provided using `t.Object(...)` schemas in the route definitions. Example validators: + * `params: t.Object({ pluginId: t.String() })` (plugin id is validated as a string param) + * `body: t.Object({ path: t.String(), state: t.Optional(t.Record(t.String(), t.Unknown())) })` + * `query: t.Object({ path: t.Optional(t.String()) })` Integration with templates and fragments -- The POST `/template` endpoint returns `template` and `fragments` objects that correspond to the Template/Fragment formats used by `@dockstat/template-renderer`. -- See the package README for the template format, builder API, parsers, and rendering components: +* The POST `/template` endpoint returns `template` and `fragments` objects that correspond to the Template/Fragment formats used by `@dockstat/template-renderer`. +* See the package README for the template format, builder API, parsers, and rendering components: ```packages/template-renderer/README.md#L1-200 # @dockstat/template-renderer ... ``` -- The renderer package exposes: - - `TemplateRenderer` component - - `parseTemplate`, `parseFragment` - - `useTemplate` hooks - - Builder helpers (programmatic creation) -- Use the returned `template` and `fragments` with `TemplateRenderer` or `useTemplate` in the frontend. +* The renderer package exposes: + * `TemplateRenderer` component + * `parseTemplate`, `parseFragment` + * `useTemplate` hooks + * Builder helpers (programmatic creation) +* Use the returned `template` and `fragments` with `TemplateRenderer` or `useTemplate` in the frontend. Error handling -- Typical error responses include: - - `400` — Validation errors (invalid body/query/params) - - `404` (implicit) — Resource not found responses are returned as JSON with `error` field (e.g. `Route not found`, `Loader not found`, `Action not found`) - - `500` — Internal server errors with structured error messages -- The API applies a global error handler that returns structured JSON errors for server-side issues. +* Typical error responses include: + * `400` — Validation errors (invalid body/query/params) + * `404` (implicit) — Resource not found responses are returned as JSON with `error` field (e.g. `Route not found`, `Loader not found`, `Action not found`) + * `500` — Internal server errors with structured error messages +* The API applies a global error handler that returns structured JSON errors for server-side issues. Examples and common workflows -- Build navigation: call GET `/plugins/frontend/navigation` and merge returned entries into your main UI navigation. -- Render a plugin route: +* Build navigation: call GET `/plugins/frontend/navigation` and merge returned entries into your main UI navigation. +* Render a plugin route: + + 1. GET the route list or navigation to find the pluginId and route path. 2. POST `/plugins/frontend/:pluginId/template` with `{ "path": "/route" }` to obtain the template + fragments + initialData. 3. Use `TemplateRenderer` (or `useTemplate`) with the returned `template`, `fragments` and `initialData` to render the plugin page client-side. - -- Execute a UI action server-side (for testing or remote triggers): POST `/plugins/frontend/:pluginId/actions/:actionId/execute` with optional state/payload. +* Execute a UI action server-side (for testing or remote triggers): POST `/plugins/frontend/:pluginId/actions/:actionId/execute` with optional state/payload. Security considerations -- These endpoints do not enforce authentication by default in the current development setup. For production, you should ensure: - - Routes are behind authenticated middleware or a reverse proxy enforcing auth. - - Only trusted clients can execute loaders/actions that may mutate state. +* These endpoints do not enforce authentication by default in the current development setup. For production, you should ensure: + * Routes are behind authenticated middleware or a reverse proxy enforcing auth. + * Only trusted clients can execute loaders/actions that may mutate state. \ No newline at end of file diff --git a/apps/docs/dockstat/patterns/README.md b/apps/docs/dockstat/patterns/README.md index 06360a29..eb1bce02 100644 --- a/apps/docs/dockstat/patterns/README.md +++ b/apps/docs/dockstat/patterns/README.md @@ -7,4 +7,4 @@ updatedAt: 2026-01-01T20:38:13.550Z urlId: bHRdz02Jsy --- -> Frontend and Backend Patterns for the Development of DockStat +> Frontend and Backend Patterns for the Development of DockStat \ No newline at end of file diff --git a/package.json b/package.json index 3c123f06..c588f19c 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "docker-up:fg": "docker compose -f docker-compose.dev.yaml up --remove-orphans", "dev": "turbo run dev", "dev:dockstat": "bun run docker-up && bun run dev --filter=@dockstat/frontend --filter=@dockstat/api --filter=@dockstat/store-verification", + "dev:dockstat/api": "bun run docker-up && bun run dev --filter=@dockstat/api", "lint": "turbo run lint", "lint:gh": "turbo run lint -- --reporter=github",