7abb048edc
Implement Keycloak authentication, protected routes, and add combobox and autocomplete components for tool categories and features. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 776963d0-f75d-42e2-a57b-cc36bdff8495 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 0b145113-c016-4f54-b000-13bd3b0ba8f0 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0683fb79-a27c-485c-9333-5f4b288c4567/776963d0-f75d-42e2-a57b-cc36bdff8495/z4uWN6A Replit-Helium-Checkpoint-Created: true
589 lines
14 KiB
YAML
589 lines
14 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
|
|
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"
|
|
|
|
/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]
|
|
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"
|
|
|
|
/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/{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
|
|
|
|
/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"
|
|
|
|
components:
|
|
schemas:
|
|
HealthStatus:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
required:
|
|
- status
|
|
|
|
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"]
|
|
features:
|
|
type: array
|
|
items:
|
|
type: string
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
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"]
|
|
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
|
|
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
|
|
features:
|
|
type: array
|
|
items:
|
|
type: string
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
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"]
|
|
|
|
ErrorResponse:
|
|
type: object
|
|
required: [error]
|
|
properties:
|
|
error:
|
|
type: string
|