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:
@@ -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
|
||||
|
||||
|
||||
@@ -67,6 +67,16 @@ erDiagram
|
||||
|
||||
eulaVersions ||--o{ eulaAgreements : "has agreements"
|
||||
|
||||
uiSettings {
|
||||
uuid id PK
|
||||
varchar namespace
|
||||
varchar key
|
||||
jsonb value
|
||||
boolean isDeleted
|
||||
timestamptz createdAt
|
||||
timestamptz updatedAt
|
||||
}
|
||||
|
||||
clients {
|
||||
varchar clientId PK
|
||||
text name UK
|
||||
@@ -318,6 +328,16 @@ erDiagram
|
||||
timestamptz agreedAt
|
||||
varchar agreedFromIp
|
||||
}
|
||||
|
||||
uiSettings {
|
||||
uuid id PK
|
||||
varchar namespace
|
||||
varchar key
|
||||
jsonb value
|
||||
boolean isDeleted
|
||||
timestamptz createdAt
|
||||
timestamptz updatedAt
|
||||
}
|
||||
```
|
||||
|
||||
## Core Entities
|
||||
@@ -589,6 +609,33 @@ CREATE INDEX idx_eulaagreements_user_time ON eulaAgreements(cognitoSubjectId, ag
|
||||
- ON DELETE RESTRICT prevents deleting EULA versions that have agreements
|
||||
- Composite indexes optimize common query patterns (agreements by version, user history)
|
||||
|
||||
### UI Settings (`uiSettings`)
|
||||
|
||||
Generic key-value store scoped by namespace for UI state (preferences, feature flags, saved filters). Added in migration 123.
|
||||
|
||||
```sql
|
||||
CREATE TABLE "uiSettings" (
|
||||
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
namespace VARCHAR(255) NOT NULL,
|
||||
key VARCHAR(255) NOT NULL,
|
||||
value JSONB NOT NULL,
|
||||
"isDeleted" BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(namespace, key)
|
||||
);
|
||||
|
||||
-- Index for list/filter by namespace; UNIQUE(namespace, key) already creates an index on (namespace, key)
|
||||
CREATE INDEX idx_uisettings_namespace ON "uiSettings"(namespace);
|
||||
```
|
||||
|
||||
**Key Features**:
|
||||
- Namespace scopes data (e.g. `demo-dashboard:{userId}`, `feature-flags:global`, `saved-filters:{clientId}`)
|
||||
- One setting per (namespace, key); value is JSONB for flexible structure
|
||||
- Soft delete via `isDeleted`; list/get exclude soft-deleted rows
|
||||
- UNIQUE(namespace, key) enforces one record per scope+key and provides an implicit index for lookups by (namespace, key)
|
||||
- Single explicit index on `namespace` for listing/filtering by namespace
|
||||
|
||||
### Queries (`queries`)
|
||||
Defines data extraction logic with type-specific implementations.
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ This document provides a comprehensive summary of all REST API endpoints availab
|
||||
| /admin/eula/{version_id}/activate | POST | EulaService |
|
||||
| /admin/eula/agreements | GET | EulaService |
|
||||
| /admin/eula/compliance | GET | EulaService |
|
||||
| /ui-settings | GET, POST | UISettingsService |
|
||||
| /ui-settings/{id} | GET, PATCH, DELETE | UISettingsService |
|
||||
|
||||
---
|
||||
|
||||
@@ -353,6 +355,30 @@ This document provides a comprehensive summary of all REST API endpoints availab
|
||||
- Defaults to current EULA version
|
||||
- Returns: `{version_id, version, total_users, agreed_count, not_agreed_count, compliance_percentage, users[], page, page_size, has_more}`
|
||||
|
||||
## UI Settings Service
|
||||
|
||||
### UI Settings Management
|
||||
- **GET /ui-settings** - List UI settings (soft-deleted excluded)
|
||||
- Query Parameters:
|
||||
- `namespace` (optional) - Filter by namespace (e.g. demo-dashboard:{userId}, feature-flags:global)
|
||||
- Returns: `{settings[], totalCount}`
|
||||
|
||||
- **POST /ui-settings** - Create a UI setting
|
||||
- Request Body: `{namespace, key, value}` (value is a JSON object)
|
||||
- Use namespace to scope data (e.g. demo-dashboard:{userId}, feature-flags:global, saved-filters:{clientId})
|
||||
- Returns: Created `UISetting` (201 Created)
|
||||
|
||||
- **GET /ui-settings/{id}** - Get a UI setting by ID
|
||||
- Returns: `{id, namespace, key, value, isDeleted, createdAt, updatedAt}` (200 OK) or 404 if not found or soft-deleted
|
||||
|
||||
- **PATCH /ui-settings/{id}** - Update a UI setting value
|
||||
- Request Body: `{value}` (new JSON object)
|
||||
- Returns: Updated `UISetting` (200 OK) or 404 if not found or soft-deleted
|
||||
|
||||
- **DELETE /ui-settings/{id}** - Soft-delete a UI setting
|
||||
- Sets `isDeleted` to true; record is retained
|
||||
- Returns: 204 No Content or 404 if not found
|
||||
|
||||
## Common Response Codes
|
||||
|
||||
All endpoints may return the following standard HTTP response codes:
|
||||
@@ -395,6 +421,7 @@ Rate limit headers included in all responses:
|
||||
- `GET /swagger/*` - Swagger UI
|
||||
- `GET /metrics` - Prometheus metrics
|
||||
- `GET /eula` - Current public EULA version
|
||||
- `GET /ui-settings`, `POST /ui-settings`, `GET /ui-settings/{id}`, `PATCH /ui-settings/{id}`, `DELETE /ui-settings/{id}` - UI settings (JWT required)
|
||||
|
||||
## API Versioning
|
||||
|
||||
|
||||
Reference in New Issue
Block a user