Merged in jmathison/demo-table (pull request #213)

Add demo dashboard settings table and CRUD API

* Add demo dashboard settings table and CRUD API

- Migration 00000000000123: create demoDashboardSettings table (id, guid, key, value JSONB, isDeleted, timestamps)
- SQLC queries and repository for create, list, listByGuid, get, update, soft delete
- OpenAPI paths and schemas in queryAPI.yaml; regenerate api.gen.go (embedded spec)
- Handlers in api/queryAPI/demodashboardsettings.go; ConfigProvider GetDBQueries for repo access
- Unit tests for demo dashboard settings CRUD

* Fix sqlc-generated demo dashboard setting types

Align demo dashboard settings handlers with sqlc output (DemoDashboardSetting model + pointer slices) so CI codegen/build succeeds.

* Fix CI gosec and gofmt issues

- Suppress gosec G115 for TotalCount len->int32 cast (consistent with other list endpoints)
- gofmt mock GetDBQueries() in test helpers

* gofmt query API demo settings

* Tighten demo dashboard settings OpenAPI constraints

* Regenerate query API embedded spec

* refactor: generic UI settings (table, API, service) and three-layer architecture

- Replace demo-dashboard-settings with generic UI settings:
  - Table uiSettings with namespace (was guid), key, value JSONB; UNIQUE(namespace, key)
  - Migration 123: create_ui_settings (single migration, no rename)
  - OpenAPI: /ui-settings, UISettingsService, UISetting schemas with namespace
  - API types and handlers: CreateUISetting, ListUISettings, GetUISetting, UpdateUISetting, DeleteUISetting

- Add service layer (architecture fix):
  - internal/uisettings: Service with Create, List, ListByNamespace, Get, Update, SoftDelete
  - Controllers call s.svc.UISettings only; remove GetDBQueries from queryAPI ConfigProvider
  - Wire UISettings in Services, main.go, and testutils

- Repository: uisettings.sql + uisettings.sql.go, UISetting model; remove demodashboardsettings
- Controller: uisettings.go (replaces demodashboardsettings.go), ErrNotFound from uisettings package
- Tests: uisettings_test.go with namespace-based list/cre…
* Add UISetting model and generated queries for uiSettings table

- models.go: add UISetting struct (sqlc 1.30.0)
- uisettings.sql.go: generated CRUD for ui_settings feature

Made-with: Cursor

* Use repository.UiSetting to match sqlc-generated type

- service and API use repository.UiSetting (sqlc struct name for uiSettings table)
- uisettings.sql.go: keep CreateUISetting/GetUISetting etc. from query names, return *UiSetting
- Fixes Docker/CI build undefined repository.UISetting

* Fix import formatting for golangci-lint

* Lint fix

* uisettings list test

* tests fixes

* Merge main: resolve api.gen.go conflicts (UI settings + DeleteDocument)

* Doc updates and elimination of index redundancy


Approved-by: Jay Brown
This commit is contained in:
Jacob Mathison
2026-03-04 23:00:50 +00:00
parent 09c61ea9b4
commit 8a4029058b
17 changed files with 1693 additions and 289 deletions
+80
View File
@@ -28,6 +28,7 @@ The API is organized into the following service groups:
| AuthService | Operations related to authentication |
| AdminService | Operations related to user management and administration |
| EulaService | Operations related to End User License Agreement management and tracking |
| UISettingsService | Operations related to UI-scoped key-value settings (per user, client, or global) |
## Authentication and Authorization
@@ -1600,6 +1601,74 @@ Returns a comprehensive compliance report showing which users have and have not
---
## UI Settings Operations (UISettingsService)
The UI Settings service provides a generic key-value store scoped by namespace. Use it for user preferences, feature flags, saved filters, or other UI state. Namespaces scope data (e.g. `demo-dashboard:{userId}`, `feature-flags:global`, `saved-filters:{clientId}`). Records use soft delete (`isDeleted`); list/get exclude soft-deleted rows.
**Security**: All UI settings endpoints require JWT authentication (auth-only, no Permit.io resource check).
#### `GET /ui-settings`
Returns settings where `isDeleted` is false. Optional query param `namespace` filters by namespace.
**Query Parameters**:
| Parameter | Type | Required | Description |
| --------- | ------ | -------- | ------------------------------------------------ |
| namespace | string | No | Filter by namespace (omit to list all). Max 255 chars. |
**Response** (`UISettingListResponse`): `{ settings: UISetting[], totalCount: number }`
**Responses**: `200` OK, `400` Bad Request, `401` Unauthorized, `429` Too Many Requests, `500` Internal Server Error
#### `POST /ui-settings`
Creates a new UI setting. Returns 201 with the created resource.
**Request Body** (`UISettingCreate`):
| Field | Type | Required | Description |
| --------- | ------ | -------- | --------------------------------------------------------------------------- |
| namespace | string | Yes | Scope for the setting (e.g. demo-dashboard:{userId}, feature-flags:global). Max 255. |
| key | string | Yes | Setting key within the namespace. Max 255. |
| value | object | Yes | JSON value (object) for the setting. |
**Response** (`UISetting`): Created setting with `id`, `namespace`, `key`, `value`, `isDeleted`, `createdAt`, `updatedAt`
**Responses**: `201` Created, `400` Bad Request, `401` Unauthorized, `429` Too Many Requests, `500` Internal Server Error
#### `GET /ui-settings/{id}`
Returns a single setting by id. Returns 404 if not found or soft-deleted.
**Path Parameters**: `id` (uuid) UI setting ID
**Response** (`UISetting`): Full setting object
**Responses**: `200` OK, `400` Bad Request, `401` Unauthorized, `404` Not Found, `429` Too Many Requests, `500` Internal Server Error
#### `PATCH /ui-settings/{id}`
Updates the value of an existing setting. Returns 404 if not found or soft-deleted.
**Path Parameters**: `id` (uuid) UI setting ID
**Request Body** (`UISettingUpdate`): `{ value: object }` New JSON value for the setting
**Response** (`UISetting`): Updated setting object
**Responses**: `200` OK, `400` Bad Request, `401` Unauthorized, `404` Not Found, `429` Too Many Requests, `500` Internal Server Error
#### `DELETE /ui-settings/{id}`
Soft-deletes a UI setting (sets `isDeleted` to true). Record is retained. Returns 204 on success, 404 if not found.
**Path Parameters**: `id` (uuid) UI setting ID
**Responses**: `204` No Content, `400` Bad Request, `401` Unauthorized, `404` Not Found, `429` Too Many Requests, `500` Internal Server Error
---
## Request/Response Schemas
### Standard Response Headers
@@ -1710,6 +1779,11 @@ The following endpoints require a valid JWT token but do **not** check Permit.io
| `GET /identity` | Users need to discover their roles |
| `GET /eula/status` | Users need to check their EULA agreement status |
| `POST /eula/agree` | Users need to be able to agree to the EULA |
| `GET /ui-settings` | List UI settings (optional namespace filter) |
| `POST /ui-settings` | Create UI setting |
| `GET /ui-settings/{id}` | Get UI setting by ID |
| `PATCH /ui-settings/{id}` | Update UI setting value |
| `DELETE /ui-settings/{id}` | Soft-delete UI setting |
### Authorization Reference Table
@@ -1775,6 +1849,12 @@ The following table shows what data is passed to Permit.io for each protected en
| `POST` | `/admin/eula/{version_id}/activate` | `admin` | `post` | Activate EULA version |
| `GET` | `/admin/eula/agreements` | `admin` | `get` | List EULA agreements |
| `GET` | `/admin/eula/compliance` | `admin` | `get` | Get compliance report |
| **UI Settings Operations** |
| `GET` | `/ui-settings` | - | - | Auth-only (no Permit.io)|
| `POST` | `/ui-settings` | - | - | Auth-only (no Permit.io)|
| `GET` | `/ui-settings/{id}` | - | - | Auth-only (no Permit.io)|
| `PATCH` | `/ui-settings/{id}` | - | - | Auth-only (no Permit.io)|
| `DELETE` | `/ui-settings/{id}` | - | - | Auth-only (no Permit.io)|
### Permit.io Configuration Requirements