tududi/backend/config/swagger.js
Chris eee1bbc013
Fix bug 722 (#737)
* Fix project statuses

* Refactor project states

* Add translations
2025-12-28 07:51:15 +02:00

350 lines
13 KiB
JavaScript

const swaggerJsdoc = require('swagger-jsdoc');
const path = require('path');
const API_VERSION = process.env.API_VERSION || 'v1';
const API_BASE_PATH = `/api/${API_VERSION}`;
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Tududi API',
version: '1.0.0',
description: 'REST API for Tududi task management application',
contact: {
name: 'Tududi',
url: 'https://github.com/chrisvel/tududi',
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
},
servers: [
{
url: 'http://localhost:3002',
description: `Backend server (base path ${API_BASE_PATH})`,
},
{
url: 'http://localhost:8080',
description: `Frontend dev server (proxy to ${API_BASE_PATH})`,
},
],
components: {
securitySchemes: {
cookieAuth: {
type: 'apiKey',
in: 'cookie',
name: 'connect.sid',
description: 'Session cookie authentication',
},
BearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description:
'JWT token authentication via Authorization header',
},
},
schemas: {
Error: {
type: 'object',
properties: {
error: {
type: 'string',
description: 'Error type',
},
message: {
type: 'string',
description: 'Error message',
},
},
},
Task: {
type: 'object',
properties: {
id: {
type: 'integer',
description: 'Task ID',
},
uid: {
type: 'string',
description: 'Task unique identifier',
},
name: {
type: 'string',
description: 'Task name',
},
description: {
type: 'string',
description:
'Task description (Markdown supported)',
},
status: {
type: 'string',
enum: ['pending', 'completed', 'archived'],
description: 'Task status',
},
priority: {
type: 'string',
enum: ['low', 'medium', 'high'],
description: 'Task priority',
},
due_date: {
type: 'string',
format: 'date-time',
description: 'Task due date',
},
project_id: {
type: 'integer',
description: 'Associated project ID',
},
recurring_pattern: {
type: 'string',
enum: ['daily', 'weekly', 'monthly', 'yearly'],
description: 'Recurring pattern',
},
created_at: {
type: 'string',
format: 'date-time',
},
updated_at: {
type: 'string',
format: 'date-time',
},
},
},
Project: {
type: 'object',
properties: {
id: {
type: 'integer',
description: 'Project ID',
},
uid: {
type: 'string',
description: 'Project unique identifier',
},
name: {
type: 'string',
description: 'Project name',
},
description: {
type: 'string',
description: 'Project description',
},
status: {
type: 'string',
enum: [
'not_started',
'planned',
'in_progress',
'waiting',
'done',
'cancelled',
],
description: 'Project status',
},
priority: {
type: 'string',
enum: ['low', 'medium', 'high'],
description: 'Project priority',
},
created_at: {
type: 'string',
format: 'date-time',
},
updated_at: {
type: 'string',
format: 'date-time',
},
},
},
Note: {
type: 'object',
properties: {
id: {
type: 'integer',
description: 'Note ID',
},
uid: {
type: 'string',
description: 'Note unique identifier',
},
title: {
type: 'string',
description: 'Note title',
},
content: {
type: 'string',
description: 'Note content (Markdown supported)',
},
color: {
type: 'string',
description: 'Note background color (hex)',
},
project_id: {
type: 'integer',
description: 'Associated project ID',
},
created_at: {
type: 'string',
format: 'date-time',
},
updated_at: {
type: 'string',
format: 'date-time',
},
},
},
Tag: {
type: 'object',
properties: {
id: {
type: 'integer',
description: 'Tag ID',
},
uid: {
type: 'string',
description: 'Tag unique identifier',
},
name: {
type: 'string',
description: 'Tag name',
},
created_at: {
type: 'string',
format: 'date-time',
},
updated_at: {
type: 'string',
format: 'date-time',
},
},
},
InboxItem: {
type: 'object',
properties: {
id: {
type: 'integer',
description: 'Inbox item ID',
},
uid: {
type: 'string',
description: 'Inbox item unique identifier',
},
content: {
type: 'string',
description: 'Inbox item content',
},
status: {
type: 'string',
enum: ['added', 'processed', 'ignored'],
description: 'Processing status',
},
created_at: {
type: 'string',
format: 'date-time',
},
updated_at: {
type: 'string',
format: 'date-time',
},
},
},
Area: {
type: 'object',
properties: {
id: {
type: 'integer',
description: 'Area ID',
},
uid: {
type: 'string',
description: 'Area unique identifier',
},
name: {
type: 'string',
description: 'Area name',
},
description: {
type: 'string',
description: 'Area description',
},
created_at: {
type: 'string',
format: 'date-time',
},
updated_at: {
type: 'string',
format: 'date-time',
},
},
},
ApiKey: {
type: 'object',
properties: {
id: { type: 'integer' },
name: {
type: 'string',
description: 'Friendly label for the API key',
},
token_prefix: {
type: 'string',
description:
'First characters displayed to help identify the key',
},
created_at: {
type: 'string',
format: 'date-time',
},
updated_at: {
type: 'string',
format: 'date-time',
},
last_used_at: {
type: 'string',
format: 'date-time',
},
expires_at: {
type: 'string',
format: 'date-time',
},
revoked_at: {
type: 'string',
format: 'date-time',
},
},
},
},
},
security: [
{
cookieAuth: [],
},
],
},
apis: [path.join(__dirname, '..', 'docs', 'swagger', '*.js')], // Path to centralized Swagger documentation files
};
const swaggerSpec = swaggerJsdoc(options);
if (swaggerSpec?.paths) {
const updatedPaths = {};
Object.entries(swaggerSpec.paths).forEach(([pathKey, pathValue]) => {
if (pathKey.startsWith('/api/')) {
const versionedPath =
API_BASE_PATH === '/api'
? pathKey
: `${API_BASE_PATH}${pathKey.slice(4)}`;
updatedPaths[versionedPath] = pathValue;
} else {
updatedPaths[pathKey] = pathValue;
}
});
swaggerSpec.paths = updatedPaths;
}
module.exports = swaggerSpec;