Removes the global app_theme, app_theme_user and app_primary_color settings from the admin/settings area and the underlying service/cache/API/i18n/docs layers. The tenant columns (tenants.primary_color, default_theme, allow_user_theme) become the single source of truth for appearance. Branding helpers are tenant-only and fall back to a hardcoded 'light' theme with no brand color when no tenant context is available (login, error, pre-session pages). The APP_THEME env var is removed. Scope: - UI: Appearance tab gone from /admin/settings; tenant edit form drops the global-fallback color preview. - Service: SettingsAppGateway no longer exposes setting-backed accessors for theme/user-theme/primary-color. Theme catalog utilities (listThemes, isAllowedTheme, normalizeTheme, resolveDefaultTheme) stay and are used across Tenant / Auth / User flows; resolveDefaultTheme now hardcodes 'light' with a catalog fallback (no global/env lookup). - AdminSettingsService: buildPageData, sanitization, audit snapshot, apply step and cache payload are all stripped of the three keys. Dead helper applyAppPrimaryColor + normalizePrimaryColor removed. - Cache: SettingCacheService HOT_PATH_KEYS drops the three keys. - API: /settings (GET/PUT) and /settings/public (GET) no longer expose appearance fields; OpenAPI schemas pruned accordingly. - Audit redaction list shortened. - DB: db/init/init.sql seed rows removed. No migration for existing installs — legacy rows stay inert. - i18n + docs: setting.app_theme, setting.app_theme_user, setting.app_primary_color removed from de+en locales; reference and explanation docs updated. - Tests: covering tests for the removed methods pruned; ThemeResolutionTest rewritten for tenant-only semantics. One unrelated PHP-CS-Fixer issue in UserRegistrar.php cleaned up to keep QG-006 green. Workflow: .agents/runs/SETTINGS-APPEARANCE-TENANT-ONLY/ (gitignored). Gates: QG-001..003, QG-006, QG-008 all pass (1985 tests, 28764 assertions). Reviews: code, security, acceptance all pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2191 lines
57 KiB
YAML
2191 lines
57 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Malphite API
|
|
version: v1
|
|
description: |
|
|
OpenAPI specification for the current `/api/v1` endpoints.
|
|
Authentication uses Bearer tokens in the format `<selector>:<token>`.
|
|
servers:
|
|
- url: /api/v1
|
|
security:
|
|
- BearerAuth: []
|
|
tags:
|
|
- name: auth
|
|
description: Public authentication endpoints (no Bearer token required)
|
|
- name: me
|
|
- name: tokens
|
|
- name: users
|
|
- name: tenants
|
|
- name: departments
|
|
- name: roles
|
|
- name: permissions
|
|
- name: settings
|
|
paths:
|
|
/auth/login:
|
|
post:
|
|
tags: [auth]
|
|
summary: Login with email and password
|
|
description: |
|
|
Authenticates a user with email and password and returns a Bearer token.
|
|
This endpoint is **public** — no Authorization header required.
|
|
|
|
The returned token can be used immediately as `Authorization: Bearer <token>`
|
|
for all subsequent API requests.
|
|
|
|
Rate limits (stricter than general API limits):
|
|
- 10 failed attempts per IP per 10 minutes
|
|
- 5 failed attempts per email+IP per 15 minutes
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginRequest'
|
|
example:
|
|
email: user@example.com
|
|
password: "..."
|
|
token_name: "My App"
|
|
responses:
|
|
'201':
|
|
description: Login successful — token issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginResponse'
|
|
'401':
|
|
description: Authentication failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
examples:
|
|
invalid_credentials:
|
|
value:
|
|
ok: false
|
|
request_id: 550e8400-e29b-41d4-a716-446655440000
|
|
error_code: invalid_credentials
|
|
details: {}
|
|
account_inactive:
|
|
value:
|
|
ok: false
|
|
request_id: 550e8400-e29b-41d4-a716-446655440000
|
|
error_code: account_inactive
|
|
details: {}
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'409':
|
|
$ref: '#/components/responses/Conflict'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me:
|
|
get:
|
|
tags: [me]
|
|
summary: Get authenticated user profile
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/MeResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [me]
|
|
summary: Update authenticated user profile
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/MeUpdateRequest'
|
|
responses:
|
|
'200':
|
|
description: Updated profile
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/MeResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [me]
|
|
summary: Patch authenticated user profile
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/MeUpdateRequest'
|
|
responses:
|
|
'200':
|
|
description: Updated profile
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/MeResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/password:
|
|
post:
|
|
tags: [me]
|
|
summary: Change password for authenticated user
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/MePasswordRequest'
|
|
responses:
|
|
'204':
|
|
description: No Content
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/avatar:
|
|
get:
|
|
tags: [me]
|
|
summary: Get avatar image for authenticated user
|
|
parameters:
|
|
- $ref: '#/components/parameters/AvatarSize'
|
|
responses:
|
|
'200':
|
|
description: Avatar binary
|
|
content:
|
|
image/jpeg: {}
|
|
image/png: {}
|
|
image/webp: {}
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [me]
|
|
summary: Upload avatar for authenticated user
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
multipart/form-data:
|
|
schema:
|
|
type: object
|
|
required: [avatar]
|
|
properties:
|
|
avatar:
|
|
type: string
|
|
format: binary
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [me]
|
|
summary: Delete avatar for authenticated user
|
|
responses:
|
|
'204':
|
|
description: No Content
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens:
|
|
get:
|
|
tags: [tokens]
|
|
summary: List current user API tokens
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit50'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [tokens]
|
|
summary: Create API token for current user
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenCreateRequest'
|
|
responses:
|
|
'201':
|
|
description: Created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenCreateResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'409':
|
|
$ref: '#/components/responses/Conflict'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [tokens]
|
|
summary: Get current user token by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [tokens]
|
|
summary: Revoke current user token by UUID
|
|
responses:
|
|
'204':
|
|
description: No Content
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens/rotate:
|
|
post:
|
|
tags: [tokens]
|
|
summary: Rotate currently used API token
|
|
requestBody:
|
|
required: false
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
responses:
|
|
'201':
|
|
description: Created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenCreateResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
$ref: '#/components/responses/Conflict'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens/revoke-all:
|
|
post:
|
|
tags: [tokens]
|
|
summary: Revoke all current user API tokens
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RevokeAllResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/users:
|
|
get:
|
|
tags: [users]
|
|
summary: List users
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderUsers'
|
|
- $ref: '#/components/parameters/Dir'
|
|
- $ref: '#/components/parameters/ActiveFilter'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [users]
|
|
summary: Create user
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserCreateRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/users/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [users]
|
|
summary: Get user by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [users]
|
|
summary: Update user by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserUpdateRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [users]
|
|
summary: Patch user by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserUpdateRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [users]
|
|
summary: Delete user by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/users/avatar/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
- $ref: '#/components/parameters/AvatarSize'
|
|
get:
|
|
tags: [users]
|
|
summary: Get avatar image by user UUID
|
|
responses:
|
|
'200':
|
|
description: Avatar binary
|
|
content:
|
|
image/jpeg: {}
|
|
image/png: {}
|
|
image/webp: {}
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/tenants:
|
|
get:
|
|
tags: [tenants]
|
|
summary: List tenants
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderTenants'
|
|
- $ref: '#/components/parameters/Dir'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [tenants]
|
|
summary: Create tenant
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantWriteRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/tenants/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [tenants]
|
|
summary: Get tenant by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [tenants]
|
|
summary: Update tenant by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [tenants]
|
|
summary: Patch tenant by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [tenants]
|
|
summary: Delete tenant by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/tenants/avatar/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
- $ref: '#/components/parameters/AvatarSize'
|
|
get:
|
|
tags: [tenants]
|
|
summary: Get avatar image by tenant UUID
|
|
responses:
|
|
'200':
|
|
description: Avatar binary
|
|
content:
|
|
image/jpeg: {}
|
|
image/png: {}
|
|
image/webp: {}
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/departments:
|
|
get:
|
|
tags: [departments]
|
|
summary: List departments
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderDepartments'
|
|
- $ref: '#/components/parameters/Dir'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [departments]
|
|
summary: Create department
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentWriteRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/departments/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [departments]
|
|
summary: Get department by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [departments]
|
|
summary: Update department by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [departments]
|
|
summary: Patch department by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [departments]
|
|
summary: Delete department by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/roles:
|
|
get:
|
|
tags: [roles]
|
|
summary: List roles
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderRoles'
|
|
- $ref: '#/components/parameters/Dir'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [roles]
|
|
summary: Create role
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleWriteRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/roles/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [roles]
|
|
summary: Get role by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [roles]
|
|
summary: Update role by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [roles]
|
|
summary: Patch role by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [roles]
|
|
summary: Delete role by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/permissions:
|
|
get:
|
|
tags: [permissions]
|
|
summary: List permissions
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderPermissions'
|
|
- $ref: '#/components/parameters/Dir'
|
|
- $ref: '#/components/parameters/ActiveFilter'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/PermissionListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/settings:
|
|
get:
|
|
tags: [settings]
|
|
summary: Get application settings snapshot
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SettingsResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [settings]
|
|
summary: Update application settings
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SettingsUpdateRequest'
|
|
responses:
|
|
'200':
|
|
description: Updated settings snapshot
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SettingsResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [settings]
|
|
summary: Patch application settings
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SettingsUpdateRequest'
|
|
responses:
|
|
'200':
|
|
description: Updated settings snapshot
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SettingsResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/settings/public:
|
|
get:
|
|
tags: [settings]
|
|
summary: Get public app settings for unauthenticated clients
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GenericDataResponse'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: selector:token
|
|
parameters:
|
|
UuidPath:
|
|
name: uuid
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
Limit25:
|
|
name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 25
|
|
Limit50:
|
|
name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 50
|
|
Offset:
|
|
name: offset
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 0
|
|
default: 0
|
|
Search:
|
|
name: search
|
|
in: query
|
|
schema:
|
|
type: string
|
|
Dir:
|
|
name: dir
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [asc, desc]
|
|
default: asc
|
|
ActiveFilter:
|
|
name: active
|
|
in: query
|
|
schema:
|
|
type: string
|
|
description: "Accepted aliases: 1, 0, true, false, active, inactive"
|
|
AvatarSize:
|
|
name: size
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 16
|
|
maximum: 1024
|
|
OrderUsers:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, first_name, last_name, display_name, email, created, modified, active, last_login_at]
|
|
default: last_name
|
|
OrderTenants:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, description, created, modified]
|
|
default: description
|
|
OrderDepartments:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, description, code, cost_center, active, created, modified]
|
|
default: description
|
|
OrderRoles:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, description, code, active, created, modified]
|
|
default: description
|
|
OrderPermissions:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [key, description, active, created]
|
|
default: key
|
|
responses:
|
|
Unauthorized:
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
ok: false
|
|
request_id: 550e8400-e29b-41d4-a716-446655440000
|
|
error_code: unauthorized
|
|
details: {}
|
|
Forbidden:
|
|
description: Forbidden
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
NotFound:
|
|
description: Not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
ok: false
|
|
request_id: 550e8400-e29b-41d4-a716-446655440000
|
|
error_code: not_found
|
|
details: {}
|
|
ValidationError:
|
|
description: Validation failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
ok: false
|
|
request_id: 550e8400-e29b-41d4-a716-446655440000
|
|
error_code: validation_error
|
|
details:
|
|
errors:
|
|
field:
|
|
- invalid_value
|
|
Conflict:
|
|
description: Conflict
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
RateLimited:
|
|
description: Rate limited
|
|
headers:
|
|
Retry-After:
|
|
schema:
|
|
type: integer
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
ok: false
|
|
request_id: 550e8400-e29b-41d4-a716-446655440000
|
|
error_code: rate_limit_exceeded
|
|
details:
|
|
retry_after: 60
|
|
ServerError:
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
DataObject:
|
|
description: Generic service response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GenericDataResponse'
|
|
schemas:
|
|
ErrorResponse:
|
|
type: object
|
|
required: [ok, request_id, error_code, details]
|
|
properties:
|
|
ok:
|
|
type: boolean
|
|
example: false
|
|
request_id:
|
|
type: string
|
|
format: uuid
|
|
error_code:
|
|
type: string
|
|
details:
|
|
type: object
|
|
additionalProperties: true
|
|
GenericDataResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
additionalProperties: true
|
|
LoginRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [email, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
description: User email address (case-insensitive)
|
|
password:
|
|
type: string
|
|
description: User password
|
|
token_name:
|
|
type: string
|
|
description: Optional label for the issued token (e.g. "iPhone App"). Defaults to "Login".
|
|
default: Login
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
description: Optional — scope the issued token to a specific tenant UUID. Must be assigned to the user.
|
|
LoginResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
required: [token, token_uuid, expires_at]
|
|
properties:
|
|
token:
|
|
type: string
|
|
description: Full Bearer token in format `selector:plaintext`. Shown only once — store securely.
|
|
example: "abc123def:456789..."
|
|
token_uuid:
|
|
type: string
|
|
format: uuid
|
|
description: UUID of the created token record (use for revocation via /me/tokens)
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
description: UTC expiry timestamp of the token
|
|
MeUpdateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
profile_description:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
short_dial:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
locale:
|
|
type: string
|
|
theme:
|
|
type: string
|
|
current_tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
MePasswordRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [current_password, password, password2]
|
|
properties:
|
|
current_password:
|
|
type: string
|
|
password:
|
|
type: string
|
|
password2:
|
|
type: string
|
|
PermissionListItem:
|
|
type: object
|
|
properties:
|
|
key:
|
|
type: string
|
|
description:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
is_system:
|
|
type: boolean
|
|
PermissionListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/PermissionListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
SettingsObject:
|
|
type: object
|
|
properties:
|
|
app_title:
|
|
type: string
|
|
app_locale:
|
|
type: string
|
|
app_registration_enabled:
|
|
type: boolean
|
|
api_token_default_ttl_days:
|
|
type: integer
|
|
nullable: true
|
|
api_token_max_ttl_days:
|
|
type: integer
|
|
nullable: true
|
|
api_cors_allowed_origins:
|
|
type: string
|
|
default_tenant_id:
|
|
type: integer
|
|
nullable: true
|
|
default_role_id:
|
|
type: integer
|
|
nullable: true
|
|
default_department_id:
|
|
type: integer
|
|
nullable: true
|
|
user_inactivity_deactivate_days:
|
|
type: integer
|
|
nullable: true
|
|
user_inactivity_delete_days:
|
|
type: integer
|
|
nullable: true
|
|
system_audit_enabled:
|
|
type: boolean
|
|
system_audit_retention_days:
|
|
type: integer
|
|
nullable: true
|
|
microsoft_shared_client_id:
|
|
type: string
|
|
microsoft_authority:
|
|
type: string
|
|
smtp_host:
|
|
type: string
|
|
smtp_port:
|
|
type: integer
|
|
nullable: true
|
|
smtp_user:
|
|
type: string
|
|
smtp_secure:
|
|
type: string
|
|
smtp_from:
|
|
type: string
|
|
smtp_from_name:
|
|
type: string
|
|
SettingsResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
$ref: '#/components/schemas/SettingsObject'
|
|
SettingsUpdateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
app_title:
|
|
type: string
|
|
app_locale:
|
|
type: string
|
|
app_registration_enabled:
|
|
type: boolean
|
|
api_token_default_ttl_days:
|
|
type: integer
|
|
nullable: true
|
|
api_token_max_ttl_days:
|
|
type: integer
|
|
nullable: true
|
|
api_cors_allowed_origins:
|
|
type: string
|
|
default_tenant_id:
|
|
type: integer
|
|
nullable: true
|
|
default_role_id:
|
|
type: integer
|
|
nullable: true
|
|
default_department_id:
|
|
type: integer
|
|
nullable: true
|
|
user_inactivity_deactivate_days:
|
|
type: integer
|
|
nullable: true
|
|
user_inactivity_delete_days:
|
|
type: integer
|
|
nullable: true
|
|
system_audit_enabled:
|
|
type: boolean
|
|
system_audit_retention_days:
|
|
type: integer
|
|
nullable: true
|
|
microsoft_shared_client_id:
|
|
type: string
|
|
microsoft_authority:
|
|
type: string
|
|
smtp_host:
|
|
type: string
|
|
smtp_port:
|
|
type: integer
|
|
nullable: true
|
|
smtp_user:
|
|
type: string
|
|
smtp_password:
|
|
type: string
|
|
smtp_secure:
|
|
type: string
|
|
smtp_from:
|
|
type: string
|
|
smtp_from_name:
|
|
type: string
|
|
RoleWriteRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [description]
|
|
properties:
|
|
description:
|
|
type: string
|
|
minLength: 1
|
|
code:
|
|
type: string
|
|
active:
|
|
type: string
|
|
description: "Accepted aliases: 1, 0, true, false, active, inactive"
|
|
DepartmentWriteRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [description, tenant_uuid]
|
|
properties:
|
|
description:
|
|
type: string
|
|
minLength: 1
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
code:
|
|
type: string
|
|
cost_center:
|
|
type: string
|
|
active:
|
|
type: string
|
|
description: "Accepted aliases: 1, 0, true, false, active, inactive"
|
|
TenantWriteRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [description, status]
|
|
properties:
|
|
description:
|
|
type: string
|
|
minLength: 1
|
|
status:
|
|
type: string
|
|
enum: [active, inactive]
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
vat_id:
|
|
type: string
|
|
tax_number:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
fax:
|
|
type: string
|
|
email:
|
|
type: string
|
|
format: email
|
|
support_email:
|
|
type: string
|
|
format: email
|
|
support_phone:
|
|
type: string
|
|
billing_email:
|
|
type: string
|
|
format: email
|
|
website:
|
|
type: string
|
|
privacy_url:
|
|
type: string
|
|
imprint_url:
|
|
type: string
|
|
primary_color:
|
|
type: string
|
|
description: "Hex color, e.g. #0f766e"
|
|
primary_color_use_default:
|
|
type: boolean
|
|
default_theme:
|
|
type: string
|
|
allow_user_theme_mode:
|
|
type: string
|
|
enum: ['', '0', '1']
|
|
UserCreateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [first_name, last_name, email, password, password2]
|
|
properties:
|
|
first_name:
|
|
type: string
|
|
minLength: 1
|
|
last_name:
|
|
type: string
|
|
minLength: 1
|
|
email:
|
|
type: string
|
|
format: email
|
|
profile_description:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
short_dial:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
hire_date:
|
|
type: string
|
|
format: date
|
|
locale:
|
|
type: string
|
|
theme:
|
|
type: string
|
|
totp_secret:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
password:
|
|
type: string
|
|
password2:
|
|
type: string
|
|
tenant_uuids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
primary_tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
role_uuids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
department_uuids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
UserUpdateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [first_name, last_name, email]
|
|
properties:
|
|
first_name:
|
|
type: string
|
|
minLength: 1
|
|
last_name:
|
|
type: string
|
|
minLength: 1
|
|
email:
|
|
type: string
|
|
format: email
|
|
profile_description:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
short_dial:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
hire_date:
|
|
type: string
|
|
format: date
|
|
locale:
|
|
type: string
|
|
theme:
|
|
type: string
|
|
totp_secret:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
password:
|
|
type: string
|
|
password2:
|
|
type: string
|
|
tenant_uuids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
primary_tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
role_uuids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
department_uuids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
TenantSummary:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
status:
|
|
type: string
|
|
AssignmentDepartment:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
AssignmentRole:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
Assignments:
|
|
type: object
|
|
properties:
|
|
tenants:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
departments:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AssignmentDepartment'
|
|
roles:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AssignmentRole'
|
|
UserCustomFieldOption:
|
|
type: object
|
|
properties:
|
|
option_key:
|
|
type: string
|
|
label:
|
|
type: string
|
|
UserCustomFieldField:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
field_key:
|
|
type: string
|
|
label:
|
|
type: string
|
|
type:
|
|
type: string
|
|
is_filterable:
|
|
type: boolean
|
|
value:
|
|
description: Type-dependent value (string, boolean, null, or array of option keys).
|
|
options:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldOption'
|
|
UserCustomFieldTenantGroup:
|
|
type: object
|
|
properties:
|
|
tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
fields:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldField'
|
|
MeResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
display_name:
|
|
type: string
|
|
email:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
locale:
|
|
type: string
|
|
current_tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
primary_tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
can_view_permissions:
|
|
type: boolean
|
|
permissions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
assignments:
|
|
$ref: '#/components/schemas/Assignments'
|
|
custom_fields:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldTenantGroup'
|
|
TokenItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
selector_prefix:
|
|
type: string
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
last_used_at:
|
|
type: string
|
|
nullable: true
|
|
last_ip:
|
|
type: string
|
|
expires_at:
|
|
type: string
|
|
nullable: true
|
|
revoked_at:
|
|
type: string
|
|
nullable: true
|
|
created:
|
|
type: string
|
|
nullable: true
|
|
is_current_token:
|
|
type: boolean
|
|
TokenListResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TokenItem'
|
|
limit:
|
|
type: integer
|
|
TokenShowResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
$ref: '#/components/schemas/TokenItem'
|
|
TokenCreateRequest:
|
|
type: object
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
TokenCreateResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
token_uuid:
|
|
type: string
|
|
format: uuid
|
|
token:
|
|
type: string
|
|
selector_prefix:
|
|
type: string
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
expires_at:
|
|
type: string
|
|
nullable: true
|
|
RevokeAllResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
revoked_count:
|
|
type: integer
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
UserListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
display_name:
|
|
type: string
|
|
email:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
created:
|
|
type: string
|
|
tenants:
|
|
type: array
|
|
items:
|
|
type: string
|
|
departments:
|
|
type: array
|
|
items:
|
|
type: string
|
|
roles:
|
|
type: array
|
|
items:
|
|
type: string
|
|
UserListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
UserShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
display_name:
|
|
type: string
|
|
email:
|
|
type: string
|
|
profile_description:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
short_dial:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
hire_date:
|
|
type: string
|
|
format: date
|
|
locale:
|
|
type: string
|
|
theme:
|
|
type: string
|
|
email_verified_at:
|
|
type: string
|
|
nullable: true
|
|
last_login_at:
|
|
type: string
|
|
nullable: true
|
|
last_login_provider:
|
|
type: string
|
|
nullable: true
|
|
active:
|
|
type: boolean
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|
|
current_tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
primary_tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
permissions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
assignments:
|
|
$ref: '#/components/schemas/Assignments'
|
|
custom_fields:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldTenantGroup'
|
|
TenantListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
status:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
created:
|
|
type: string
|
|
TenantListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TenantListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
TenantShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
status:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
vat_id:
|
|
type: string
|
|
tax_number:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
fax:
|
|
type: string
|
|
email:
|
|
type: string
|
|
support_email:
|
|
type: string
|
|
support_phone:
|
|
type: string
|
|
billing_email:
|
|
type: string
|
|
website:
|
|
type: string
|
|
privacy_url:
|
|
type: string
|
|
imprint_url:
|
|
type: string
|
|
primary_color:
|
|
type: string
|
|
primary_color_use_default:
|
|
type: boolean
|
|
default_theme:
|
|
type: string
|
|
allow_user_theme_mode:
|
|
type: string
|
|
enum: ['', '0', '1']
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|
|
DepartmentListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
tenant_labels:
|
|
type: array
|
|
items:
|
|
type: string
|
|
created:
|
|
type: string
|
|
DepartmentListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/DepartmentListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
DepartmentShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
cost_center:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|
|
RoleListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
created:
|
|
type: string
|
|
RoleListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/RoleListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
RoleShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
permission_keys:
|
|
type: array
|
|
items:
|
|
type: string
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|