bcae59626f
Build & Push Docker Image / build (push) Successful in 2m16s
- Synchronizer token stored in session; GET /auth/csrf to obtain it - csrfProtection middleware requires X-CSRF-Token on non-safe methods - customFetch injects the header via setCsrfTokenGetter - toolrate boot loads token; reload after local login (session regenerate) - OpenAPI GET /auth/csrf + CsrfToken schema, orval regenerated
1381 lines
34 KiB
YAML
1381 lines
34 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
# Do not change the title, if the title changes, the import paths will be broken
|
|
title: Api
|
|
version: 0.1.0
|
|
description: ToolRate API — Tool listing and rating platform
|
|
servers:
|
|
- url: /api
|
|
description: Base API path
|
|
tags:
|
|
- name: health
|
|
description: Health operations
|
|
- name: tools
|
|
description: Tool management
|
|
- name: ratings
|
|
description: Tool ratings
|
|
- name: analytics
|
|
description: Analytics and aggregated statistics
|
|
- name: auth
|
|
description: Authentication
|
|
- name: users
|
|
description: User management (admin only)
|
|
- name: audit
|
|
description: Audit log
|
|
paths:
|
|
/healthz:
|
|
get:
|
|
operationId: healthCheck
|
|
tags: [health]
|
|
summary: Health check
|
|
description: Returns server health status
|
|
responses:
|
|
"200":
|
|
description: Healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/HealthStatus"
|
|
|
|
/version:
|
|
get:
|
|
operationId: getVersion
|
|
tags: [health]
|
|
summary: Build version information
|
|
description: Returns the running build version, commit SHA and build date
|
|
responses:
|
|
"200":
|
|
description: Version information
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/VersionInfo"
|
|
|
|
/tools:
|
|
get:
|
|
operationId: listTools
|
|
tags: [tools]
|
|
summary: List all tools
|
|
parameters:
|
|
- name: category
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: search
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: sort
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
enum: [newest, top_rated, most_reviewed, name_asc, name_desc, recently_updated]
|
|
- name: tags
|
|
in: query
|
|
required: false
|
|
description: Comma-separated tags; tool must include all of them
|
|
schema:
|
|
type: string
|
|
- name: features
|
|
in: query
|
|
required: false
|
|
description: Comma-separated features; tool must include all of them
|
|
schema:
|
|
type: string
|
|
- name: minRating
|
|
in: query
|
|
required: false
|
|
description: Minimum average combined rating (0-5)
|
|
schema:
|
|
type: number
|
|
minimum: 0
|
|
maximum: 5
|
|
responses:
|
|
"200":
|
|
description: List of tools
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ToolWithStats"
|
|
post:
|
|
operationId: createTool
|
|
tags: [tools]
|
|
summary: Create a new tool
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ToolInput"
|
|
responses:
|
|
"201":
|
|
description: Created tool
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Tool"
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/compare:
|
|
get:
|
|
operationId: listCompareTools
|
|
tags: [tools]
|
|
summary: Compare tools side by side (premium)
|
|
parameters:
|
|
- name: ids
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
description: Comma-separated tool ids
|
|
responses:
|
|
"200":
|
|
description: Tools in requested order
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ToolWithStats"
|
|
"401":
|
|
description: Authentication required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"403":
|
|
description: Premium feature required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/tools/{id}/rating-history:
|
|
get:
|
|
operationId: getToolRatingHistory
|
|
tags: [tools]
|
|
summary: Get a tool's rating history over time
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Rating history
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/RatingHistoryItem"
|
|
"400":
|
|
description: Invalid id
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/tools/{id}:
|
|
get:
|
|
operationId: getTool
|
|
tags: [tools]
|
|
summary: Get a tool by ID
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Tool details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ToolWithStats"
|
|
"404":
|
|
description: Not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
patch:
|
|
operationId: updateTool
|
|
tags: [tools]
|
|
summary: Update a tool
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ToolUpdate"
|
|
responses:
|
|
"200":
|
|
description: Updated tool
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Tool"
|
|
"404":
|
|
description: Not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
delete:
|
|
operationId: deleteTool
|
|
tags: [tools]
|
|
summary: Delete a tool
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"204":
|
|
description: Deleted
|
|
"404":
|
|
description: Not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/tools/trash:
|
|
get:
|
|
operationId: listTrashedTools
|
|
tags: [tools]
|
|
summary: List trashed (soft-deleted) tools
|
|
parameters:
|
|
- name: search
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: List of trashed tools
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Tool"
|
|
"403":
|
|
description: Feature "trash" requires a higher tier
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
post:
|
|
operationId: trashTools
|
|
tags: [tools]
|
|
summary: Move tools to trash (admin)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TrashToolsInput"
|
|
responses:
|
|
"200":
|
|
description: Tools trashed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
trashed:
|
|
type: integer
|
|
"403":
|
|
description: Admin required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
delete:
|
|
operationId: deleteTrashedTools
|
|
tags: [tools]
|
|
summary: Permanently delete trashed tools (admin)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TrashToolsInput"
|
|
responses:
|
|
"204":
|
|
description: Deleted
|
|
"403":
|
|
description: Admin required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/tools/trash/restore:
|
|
post:
|
|
operationId: restoreTools
|
|
tags: [tools]
|
|
summary: Restore trashed tools
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/TrashToolsInput"
|
|
responses:
|
|
"200":
|
|
description: Tools restored
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
restored:
|
|
type: integer
|
|
"403":
|
|
description: Feature "trash" requires a higher tier
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/tools/trash/empty:
|
|
post:
|
|
operationId: emptyTrash
|
|
tags: [tools]
|
|
summary: Permanently delete all trashed tools (admin)
|
|
responses:
|
|
"200":
|
|
description: Trash emptied
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
deleted:
|
|
type: integer
|
|
"403":
|
|
description: Admin required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/tools/{id}/ratings:
|
|
get:
|
|
operationId: listToolRatings
|
|
tags: [ratings]
|
|
summary: List ratings for a tool
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Ratings list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Rating"
|
|
post:
|
|
operationId: createRating
|
|
tags: [ratings]
|
|
summary: Submit a rating for a tool
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RatingInput"
|
|
responses:
|
|
"201":
|
|
description: Created rating
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Rating"
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"404":
|
|
description: Tool not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/analytics/summary:
|
|
get:
|
|
operationId: getAnalyticsSummary
|
|
tags: [analytics]
|
|
summary: Overall platform statistics
|
|
responses:
|
|
"200":
|
|
description: Platform-level summary stats
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AnalyticsSummary"
|
|
|
|
/analytics/top-tools:
|
|
get:
|
|
operationId: getTopTools
|
|
tags: [analytics]
|
|
summary: Top-rated tools
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
- name: metric
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
enum: [usefulness, usability, combined]
|
|
responses:
|
|
"200":
|
|
description: Top tools list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/TopToolEntry"
|
|
|
|
/analytics/by-category:
|
|
get:
|
|
operationId: getAnalyticsByCategory
|
|
tags: [analytics]
|
|
summary: Rating statistics grouped by category
|
|
responses:
|
|
"200":
|
|
description: Per-category statistics
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/CategoryStats"
|
|
|
|
/analytics/rating-distribution:
|
|
get:
|
|
operationId: getRatingDistribution
|
|
tags: [analytics]
|
|
summary: Distribution of rating scores across the platform
|
|
parameters:
|
|
- name: toolId
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Rating score distribution
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/RatingDistribution"
|
|
|
|
/categories:
|
|
get:
|
|
operationId: listCategories
|
|
tags: [tools]
|
|
summary: List all distinct tool categories
|
|
responses:
|
|
"200":
|
|
description: Categories list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
/features/all:
|
|
get:
|
|
operationId: listAllFeatures
|
|
tags: [tools]
|
|
summary: List all distinct feature strings across all tools
|
|
responses:
|
|
"200":
|
|
description: All known features
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
/tags/all:
|
|
get:
|
|
operationId: listAllTags
|
|
tags: [tools]
|
|
summary: List all distinct tag strings across all tools
|
|
responses:
|
|
"200":
|
|
description: All known tags
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
/auth/mode:
|
|
get:
|
|
operationId: getAuthMode
|
|
tags: [auth]
|
|
summary: Get authentication mode (oidc or local)
|
|
responses:
|
|
"200":
|
|
description: Auth mode
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AuthMode"
|
|
|
|
/auth/csrf:
|
|
get:
|
|
operationId: getCsrfToken
|
|
tags: [auth]
|
|
summary: Get a CSRF token for state-changing requests
|
|
responses:
|
|
"200":
|
|
description: CSRF token
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CsrfToken"
|
|
|
|
/auth/login:
|
|
post:
|
|
operationId: localLogin
|
|
tags: [auth]
|
|
summary: Local username/password login
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/LocalLoginInput"
|
|
responses:
|
|
"200":
|
|
description: Logged in successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AuthUser"
|
|
"401":
|
|
description: Invalid credentials
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/auth/me:
|
|
get:
|
|
operationId: getMe
|
|
tags: [auth]
|
|
summary: Get current authenticated user
|
|
responses:
|
|
"200":
|
|
description: Current user info
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AuthUser"
|
|
"401":
|
|
description: Not authenticated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/auth/me/password:
|
|
post:
|
|
operationId: changeMyPassword
|
|
tags: [auth]
|
|
summary: Change own password (local users only)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ChangePasswordInput"
|
|
responses:
|
|
"204":
|
|
description: Password changed
|
|
"400":
|
|
description: Invalid input or wrong current password
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"401":
|
|
description: Not authenticated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"422":
|
|
description: OIDC user - password is managed by the identity provider
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"429":
|
|
description: Too many attempts
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/auth/password-redirect:
|
|
get:
|
|
operationId: getPasswordRedirect
|
|
tags: [auth]
|
|
summary: Get redirect URL for managing credentials in the identity provider
|
|
responses:
|
|
"200":
|
|
description: Redirect URL (null in local mode)
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PasswordRedirect"
|
|
|
|
/auth/me/preferences:
|
|
get:
|
|
operationId: getMePreferences
|
|
tags: [auth]
|
|
summary: Get current user's browse preferences
|
|
responses:
|
|
"200":
|
|
description: User preferences
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UserPreferences"
|
|
"401":
|
|
description: Not authenticated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
put:
|
|
operationId: updateMePreferences
|
|
tags: [auth]
|
|
summary: Update current user's browse preferences
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UserPreferences"
|
|
responses:
|
|
"200":
|
|
description: Updated preferences
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UserPreferences"
|
|
"401":
|
|
description: Not authenticated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/auth/me/watchlist:
|
|
get:
|
|
operationId: getMeWatchlist
|
|
tags: [auth]
|
|
summary: Get current user's watchlist tools (premium)
|
|
responses:
|
|
"200":
|
|
description: Watchlist tools in saved order
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ToolWithStats"
|
|
"401":
|
|
description: Not authenticated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"403":
|
|
description: Premium feature required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/users:
|
|
get:
|
|
operationId: listUsers
|
|
tags: [users]
|
|
summary: List all local users (admin only)
|
|
responses:
|
|
"200":
|
|
description: User list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/User"
|
|
"401":
|
|
description: Not authenticated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"403":
|
|
description: Forbidden
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
post:
|
|
operationId: createUser
|
|
tags: [users]
|
|
summary: Create a new local user (admin only)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UserCreateInput"
|
|
responses:
|
|
"201":
|
|
description: Created user
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/User"
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"409":
|
|
description: Username already exists
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/users/{id}:
|
|
patch:
|
|
operationId: updateUser
|
|
tags: [users]
|
|
summary: Update user role (admin only)
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/UserRoleUpdate"
|
|
responses:
|
|
"200":
|
|
description: Updated user
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/User"
|
|
"404":
|
|
description: User not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
delete:
|
|
operationId: deleteUser
|
|
tags: [users]
|
|
summary: Delete a user (admin only)
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"204":
|
|
description: Deleted
|
|
|
|
/users/{id}/password:
|
|
patch:
|
|
operationId: setUserPassword
|
|
tags: [users]
|
|
summary: Set/reset a user's password (admin only, local users only)
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/SetPasswordInput"
|
|
responses:
|
|
"204":
|
|
description: Password updated
|
|
"400":
|
|
description: Validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"404":
|
|
description: User not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"422":
|
|
description: OIDC user - password is managed by the identity provider
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
"429":
|
|
description: Too many attempts
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ErrorResponse"
|
|
|
|
/audit-logs:
|
|
get:
|
|
operationId: listAuditLogs
|
|
tags: [audit]
|
|
summary: List audit log entries (admin only)
|
|
parameters:
|
|
- name: entityType
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: entityId
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
- name: limit
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
"200":
|
|
description: Audit log entries
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/AuditLog"
|
|
|
|
components:
|
|
schemas:
|
|
HealthStatus:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
required:
|
|
- status
|
|
|
|
VersionInfo:
|
|
type: object
|
|
required: [version]
|
|
properties:
|
|
version:
|
|
type: string
|
|
commitSha:
|
|
type: ["string", "null"]
|
|
buildDate:
|
|
type: ["string", "null"]
|
|
trashRetentionDays:
|
|
type: integer
|
|
|
|
AuthMode:
|
|
type: object
|
|
required: [mode]
|
|
properties:
|
|
mode:
|
|
type: string
|
|
enum: [oidc, local]
|
|
|
|
CsrfToken:
|
|
type: object
|
|
required: [token]
|
|
properties:
|
|
token:
|
|
type: string
|
|
|
|
LocalLoginInput:
|
|
type: object
|
|
required: [username, password]
|
|
properties:
|
|
username:
|
|
type: string
|
|
password:
|
|
type: string
|
|
|
|
User:
|
|
type: object
|
|
required: [id, username, role, createdAt]
|
|
properties:
|
|
id:
|
|
type: integer
|
|
username:
|
|
type: string
|
|
email:
|
|
type: ["string", "null"]
|
|
role:
|
|
type: string
|
|
enum: [admin, user]
|
|
tier:
|
|
type: string
|
|
enum: [free, premium, enterprise]
|
|
authProvider:
|
|
type: string
|
|
enum: [local, oidc]
|
|
default: local
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
UserCreateInput:
|
|
type: object
|
|
required: [username, password]
|
|
properties:
|
|
username:
|
|
type: string
|
|
minLength: 2
|
|
password:
|
|
type: string
|
|
minLength: 6
|
|
email:
|
|
type: string
|
|
role:
|
|
type: string
|
|
enum: [admin, user]
|
|
tier:
|
|
type: string
|
|
enum: [free, premium, enterprise]
|
|
|
|
UserRoleUpdate:
|
|
type: object
|
|
properties:
|
|
role:
|
|
type: string
|
|
enum: [admin, user]
|
|
tier:
|
|
type: string
|
|
enum: [free, premium, enterprise]
|
|
|
|
ChangePasswordInput:
|
|
type: object
|
|
required: [currentPassword, newPassword]
|
|
properties:
|
|
currentPassword:
|
|
type: string
|
|
minLength: 1
|
|
newPassword:
|
|
type: string
|
|
minLength: 6
|
|
|
|
SetPasswordInput:
|
|
type: object
|
|
required: [password]
|
|
properties:
|
|
password:
|
|
type: string
|
|
minLength: 6
|
|
|
|
PasswordRedirect:
|
|
type: object
|
|
required: [url]
|
|
properties:
|
|
url:
|
|
type: ["string", "null"]
|
|
|
|
AuditLog:
|
|
type: object
|
|
required: [id, entityType, action, userId, username, createdAt]
|
|
properties:
|
|
id:
|
|
type: integer
|
|
entityType:
|
|
type: string
|
|
entityId:
|
|
type: ["integer", "null"]
|
|
action:
|
|
type: string
|
|
userId:
|
|
type: string
|
|
username:
|
|
type: string
|
|
changes:
|
|
type: ["string", "null"]
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
Tool:
|
|
type: object
|
|
required: [id, name, description, category, createdAt, updatedAt]
|
|
properties:
|
|
id:
|
|
type: integer
|
|
name:
|
|
type: string
|
|
description:
|
|
type: string
|
|
category:
|
|
type: string
|
|
websiteUrl:
|
|
type: ["string", "null"]
|
|
iconUrl:
|
|
type: ["string", "null"]
|
|
createdBy:
|
|
type: ["string", "null"]
|
|
features:
|
|
type: array
|
|
items:
|
|
type: string
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
deletedAt:
|
|
type: ["string", "null"]
|
|
format: date-time
|
|
deletedBy:
|
|
type: ["string", "null"]
|
|
|
|
RatingHistoryItem:
|
|
type: object
|
|
required: [date, usefulness, usability, combined]
|
|
properties:
|
|
date:
|
|
type: string
|
|
format: date-time
|
|
usefulness:
|
|
type: number
|
|
usability:
|
|
type: number
|
|
combined:
|
|
type: number
|
|
|
|
ToolWithStats:
|
|
type: object
|
|
required: [id, name, description, category, createdAt, updatedAt, ratingCount, avgUsefulness, avgUsability, avgCombined]
|
|
properties:
|
|
id:
|
|
type: integer
|
|
name:
|
|
type: string
|
|
description:
|
|
type: string
|
|
category:
|
|
type: string
|
|
websiteUrl:
|
|
type: ["string", "null"]
|
|
iconUrl:
|
|
type: ["string", "null"]
|
|
createdBy:
|
|
type: ["string", "null"]
|
|
features:
|
|
type: array
|
|
items:
|
|
type: string
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
ratingCount:
|
|
type: integer
|
|
avgUsefulness:
|
|
type: ["number", "null"]
|
|
avgUsability:
|
|
type: ["number", "null"]
|
|
avgCombined:
|
|
type: ["number", "null"]
|
|
|
|
ToolInput:
|
|
type: object
|
|
required: [name, description, category]
|
|
properties:
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type: string
|
|
minLength: 1
|
|
category:
|
|
type: string
|
|
minLength: 1
|
|
websiteUrl:
|
|
type: string
|
|
iconUrl:
|
|
type: string
|
|
features:
|
|
type: array
|
|
items:
|
|
type: string
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
ToolUpdate:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
minLength: 1
|
|
description:
|
|
type: string
|
|
category:
|
|
type: string
|
|
websiteUrl:
|
|
type: ["string", "null"]
|
|
iconUrl:
|
|
type: ["string", "null"]
|
|
features:
|
|
type: array
|
|
items:
|
|
type: string
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
TrashToolsInput:
|
|
type: object
|
|
required: [ids]
|
|
properties:
|
|
ids:
|
|
type: array
|
|
minItems: 1
|
|
maxItems: 500
|
|
items:
|
|
type: integer
|
|
|
|
Rating:
|
|
type: object
|
|
required: [id, toolId, usefulness, usability, createdAt]
|
|
properties:
|
|
id:
|
|
type: integer
|
|
toolId:
|
|
type: integer
|
|
usefulness:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 5
|
|
usability:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 5
|
|
comment:
|
|
type: ["string", "null"]
|
|
reviewerName:
|
|
type: ["string", "null"]
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
RatingInput:
|
|
type: object
|
|
required: [usefulness, usability]
|
|
properties:
|
|
usefulness:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 5
|
|
usability:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 5
|
|
comment:
|
|
type: string
|
|
reviewerName:
|
|
type: string
|
|
|
|
AnalyticsSummary:
|
|
type: object
|
|
required: [totalTools, totalRatings, avgUsefulness, avgUsability, avgCombined, categoriesCount]
|
|
properties:
|
|
totalTools:
|
|
type: integer
|
|
totalRatings:
|
|
type: integer
|
|
avgUsefulness:
|
|
type: ["number", "null"]
|
|
avgUsability:
|
|
type: ["number", "null"]
|
|
avgCombined:
|
|
type: ["number", "null"]
|
|
categoriesCount:
|
|
type: integer
|
|
mostRatedTool:
|
|
$ref: "#/components/schemas/ToolWithStats"
|
|
|
|
TopToolEntry:
|
|
type: object
|
|
required: [tool, score, ratingCount]
|
|
properties:
|
|
tool:
|
|
$ref: "#/components/schemas/ToolWithStats"
|
|
score:
|
|
type: number
|
|
ratingCount:
|
|
type: integer
|
|
|
|
CategoryStats:
|
|
type: object
|
|
required: [category, toolCount, totalRatings, avgUsefulness, avgUsability]
|
|
properties:
|
|
category:
|
|
type: string
|
|
toolCount:
|
|
type: integer
|
|
totalRatings:
|
|
type: integer
|
|
avgUsefulness:
|
|
type: ["number", "null"]
|
|
avgUsability:
|
|
type: ["number", "null"]
|
|
|
|
RatingDistribution:
|
|
type: object
|
|
required: [usefulness, usability]
|
|
properties:
|
|
usefulness:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ScoreBucket"
|
|
usability:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ScoreBucket"
|
|
|
|
ScoreBucket:
|
|
type: object
|
|
required: [score, count]
|
|
properties:
|
|
score:
|
|
type: integer
|
|
count:
|
|
type: integer
|
|
|
|
AuthUser:
|
|
type: object
|
|
required: [sub]
|
|
properties:
|
|
sub:
|
|
type: string
|
|
email:
|
|
type: ["string", "null"]
|
|
name:
|
|
type: ["string", "null"]
|
|
preferredUsername:
|
|
type: ["string", "null"]
|
|
role:
|
|
type: string
|
|
enum: [admin, user]
|
|
tier:
|
|
type: string
|
|
enum: [free, premium, enterprise]
|
|
entitlements:
|
|
type: array
|
|
items:
|
|
type: string
|
|
isLocal:
|
|
type: boolean
|
|
|
|
UserPreferences:
|
|
type: object
|
|
properties:
|
|
view:
|
|
type: string
|
|
enum: [grid, table, rows]
|
|
density:
|
|
type: string
|
|
enum: [cozy, compact]
|
|
watchlist:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
|
|
ErrorResponse:
|
|
type: object
|
|
required: [error]
|
|
properties:
|
|
error:
|
|
type: string
|