/** * Credential template management endpoints */ import { FastifyInstance } from 'fastify'; import { createCredentialTemplate, getCredentialTemplate, getCredentialTemplateByName, listCredentialTemplates, updateCredentialTemplate, createTemplateVersion, renderCredentialFromTemplate, } from '@the-order/database'; import { createBodySchema, authenticateJWT, requireRole } from '@the-order/shared'; export async function registerTemplateRoutes(server: FastifyInstance): Promise { // Create template server.post( '/templates', { preHandler: [authenticateJWT, requireRole('admin', 'issuer')], schema: { ...createBodySchema({ type: 'object', required: ['name', 'credential_type', 'template_data'], properties: { name: { type: 'string' }, description: { type: 'string' }, credential_type: { type: 'array', items: { type: 'string' } }, template_data: { type: 'object' }, version: { type: 'number' }, is_active: { type: 'boolean' }, }, }), description: 'Create a credential template', tags: ['templates'], }, }, async (request, reply) => { const body = request.body as { name: string; description?: string; credential_type: string[]; template_data: Record; version?: number; is_active?: boolean; }; const user = (request as any).user; const template = await createCredentialTemplate({ name: body.name, description: body.description, credential_type: body.credential_type, template_data: body.template_data, version: body.version || 1, is_active: body.is_active !== false, created_by: user?.id || null, }); return reply.send(template); } ); // Get template by ID server.get( '/templates/:id', { preHandler: [authenticateJWT], schema: { params: { type: 'object', properties: { id: { type: 'string' }, }, }, description: 'Get credential template by ID', tags: ['templates'], }, }, async (request, reply) => { const { id } = request.params as { id: string }; const template = await getCredentialTemplate(id); if (!template) { return reply.code(404).send({ error: 'Template not found' }); } return reply.send(template); } ); // Get template by name server.get( '/templates/name/:name', { preHandler: [authenticateJWT], schema: { params: { type: 'object', properties: { name: { type: 'string' }, }, }, querystring: { type: 'object', properties: { version: { type: 'number' }, }, }, description: 'Get credential template by name', tags: ['templates'], }, }, async (request, reply) => { const { name } = request.params as { name: string }; const { version } = request.query as { version?: number }; const template = await getCredentialTemplateByName(name, version); if (!template) { return reply.code(404).send({ error: 'Template not found' }); } return reply.send(template); } ); // List templates server.get( '/templates', { preHandler: [authenticateJWT], schema: { querystring: { type: 'object', properties: { activeOnly: { type: 'boolean' }, limit: { type: 'number' }, offset: { type: 'number' }, }, }, description: 'List credential templates', tags: ['templates'], }, }, async (request, reply) => { const { activeOnly, limit, offset } = request.query as { activeOnly?: boolean; limit?: number; offset?: number; }; const templates = await listCredentialTemplates( activeOnly !== false, limit || 100, offset || 0 ); return reply.send({ templates }); } ); // Update template server.patch( '/templates/:id', { preHandler: [authenticateJWT, requireRole('admin', 'issuer')], schema: { params: { type: 'object', properties: { id: { type: 'string' }, }, }, ...createBodySchema({ type: 'object', properties: { description: { type: 'string' }, template_data: { type: 'object' }, is_active: { type: 'boolean' }, }, }), description: 'Update credential template', tags: ['templates'], }, }, async (request, reply) => { const { id } = request.params as { id: string }; const body = request.body as { description?: string; template_data?: Record; is_active?: boolean; }; const template = await updateCredentialTemplate(id, body); if (!template) { return reply.code(404).send({ error: 'Template not found' }); } return reply.send(template); } ); // Create new template version server.post( '/templates/:id/version', { preHandler: [authenticateJWT, requireRole('admin', 'issuer')], schema: { params: { type: 'object', properties: { id: { type: 'string' }, }, }, ...createBodySchema({ type: 'object', properties: { template_data: { type: 'object' }, description: { type: 'string' }, }, }), description: 'Create new version of credential template', tags: ['templates'], }, }, async (request, reply) => { const { id } = request.params as { id: string }; const body = request.body as { template_data?: Record; description?: string; }; const template = await createTemplateVersion(id, body); return reply.send(template); } ); // Render template with variables server.post( '/templates/:id/render', { preHandler: [authenticateJWT], schema: { params: { type: 'object', properties: { id: { type: 'string' }, }, }, ...createBodySchema({ type: 'object', required: ['variables'], properties: { variables: { type: 'object' }, }, }), description: 'Render credential template with variables', tags: ['templates'], }, }, async (request, reply) => { const { id } = request.params as { id: string }; const { variables } = request.body as { variables: Record }; const template = await getCredentialTemplate(id); if (!template) { return reply.code(404).send({ error: 'Template not found' }); } const rendered = renderCredentialFromTemplate(template, variables); return reply.send({ rendered }); } ); }