feat(F-048): completed feature
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
import type { FastifyRequest } from 'fastify';
|
||||
import { AppError } from './errors.js';
|
||||
|
||||
export type Role = 'customer' | 'admin';
|
||||
export type Role = 'customer' | 'admin' | 'editor';
|
||||
|
||||
export interface CurrentUser {
|
||||
id: string;
|
||||
|
||||
127
project/src/shared/swagger.ts
Normal file
127
project/src/shared/swagger.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* OpenAPI 3.0 configuration and shared schemas for the API.
|
||||
* Route-level schemas are defined in each module's routes file.
|
||||
*/
|
||||
import type { FastifySchema } from 'fastify';
|
||||
|
||||
export const swaggerConfig = {
|
||||
openapi: {
|
||||
openapi: '3.0.3',
|
||||
info: {
|
||||
title: 'mercadodevida API',
|
||||
description:
|
||||
'API REST completa del e-commerce mercadodevida. ' +
|
||||
'Incluye gestión de productos, catálogo, carrito, pedidos, pagos, ' +
|
||||
'CMS, reseñas, promociones, inventario, precios y configuración de tienda.',
|
||||
version: '1.0.0',
|
||||
contact: {
|
||||
name: 'Soporte mercadodevida',
|
||||
email: 'soporte@mercadodevida.com',
|
||||
},
|
||||
license: {
|
||||
name: 'MIT',
|
||||
url: 'https://opensource.org/licenses/MIT',
|
||||
},
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: 'http://localhost:3000',
|
||||
description: 'Desarrollo local',
|
||||
},
|
||||
],
|
||||
tags: [
|
||||
{ name: 'Health', description: 'Health checks' },
|
||||
{ name: 'Auth', description: 'Autenticación y sesiones' },
|
||||
{ name: 'Catalog', description: 'Catálogo de productos (público)' },
|
||||
{ name: 'Admin Products', description: 'Gestión de productos (admin)' },
|
||||
{ name: 'Cart', description: 'Carrito de compras' },
|
||||
{ name: 'Checkout', description: 'Proceso de compra' },
|
||||
{ name: 'Orders', description: 'Pedidos' },
|
||||
{ name: 'Payments', description: 'Pagos y transacciones' },
|
||||
{ name: 'Users', description: 'Gestión de usuarios y perfiles' },
|
||||
{ name: 'Categories', description: 'Categorías' },
|
||||
{ name: 'Brands', description: 'Marcas' },
|
||||
{ name: 'Inventory', description: 'Inventario y stock' },
|
||||
{ name: 'Pricing', description: 'Precios y IVA' },
|
||||
{ name: 'Shipping', description: 'Envíos y zonas' },
|
||||
{ name: 'Promotions', description: 'Promociones y cupones' },
|
||||
{ name: 'Reviews', description: 'Reseñas de productos' },
|
||||
{ name: 'CMS', description: 'Páginas de contenido' },
|
||||
{ name: 'Admin', description: 'Panel de administración' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// ── Shared schemas ─────────────────────────────────────────────────────────────
|
||||
|
||||
export const errorSchema = {
|
||||
type: 'object',
|
||||
required: ['error', 'requestId'],
|
||||
properties: {
|
||||
error: {
|
||||
type: 'object',
|
||||
required: ['statusCode', 'code', 'message'],
|
||||
properties: {
|
||||
statusCode: { type: 'integer' },
|
||||
code: { type: 'string' },
|
||||
message: { type: 'string' },
|
||||
details: { type: 'array', items: { type: 'object', additionalProperties: true } },
|
||||
},
|
||||
},
|
||||
requestId: { type: 'string' },
|
||||
},
|
||||
};
|
||||
|
||||
export const paginationQuerySchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
limit: {
|
||||
type: 'integer',
|
||||
minimum: 1,
|
||||
maximum: 100,
|
||||
default: 20,
|
||||
description: 'Resultados por página',
|
||||
},
|
||||
offset: {
|
||||
type: 'integer',
|
||||
minimum: 0,
|
||||
default: 0,
|
||||
description: 'Desplazamiento desde el inicio',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const paginationResponseSchema = (itemSchema: Record<string, unknown>) => ({
|
||||
type: 'object',
|
||||
properties: {
|
||||
items: { type: 'array', items: itemSchema },
|
||||
total: { type: 'integer', description: 'Total de registros' },
|
||||
},
|
||||
});
|
||||
|
||||
// ── Common route config helpers ───────────────────────────────────────────────
|
||||
|
||||
/** Mark a route as requiring authentication. */
|
||||
export function withAuth(schema: FastifySchema): FastifySchema {
|
||||
return {
|
||||
...schema,
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cookie: { type: 'string', description: 'mdv_session cookie de sesión' },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Mark a route as admin-only. */
|
||||
export function withAdmin(schema: FastifySchema): FastifySchema {
|
||||
return withAuth({
|
||||
...schema,
|
||||
response: {
|
||||
...(schema.response ?? {}),
|
||||
401: errorSchema,
|
||||
403: errorSchema,
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user