Skip to content

Templates Module - Módulo de Templates

Nota: O fluxo de upload migrou de PDF para DOCX. Consulte docs/architecture/html-template-migration.md para detalhes da migração.

Endpoints de Templates

Listagem e CRUD

EndpointMétodoDescrição
/templatesGETLista templates com filtros opcionais
/templates/:idGETRetorna um template pelo ID
/templatesPOSTCria um novo template
/templates/:idPUTAtualiza um template existente
/templates/:idDELETERemove um template
/templates/recent-pdfsGETLista PDFs enviados recentemente

PDFs Recentes (Recent PDFs)

EndpointMétodoDescrição
/templates/recent-pdfsGETLista PDFs já enviados para reutilização

Query Parameters:

ParâmetroTipoObrigatórioDescrição
searchstringNãoFiltro por nome do arquivo (case insensitive)

Response:

typescript
type RecentPdf = {
  id: string           // UUID do arquivo no storage
  fileName: string     // Nome do arquivo definido pelo usuário
  filePath: string     // Caminho: templates/{companyId}/{uuid}.pdf
  fileSize: number     // Tamanho em bytes
  uploadedAt: Date     // Data/hora do upload
}

// Response: RecentPdf[]

Exemplo de Request:

GET /templates/recent-pdfs
GET /templates/recent-pdfs?search=contrato

Exemplo de Response:

json
[
  {
    "id": "pdf-001",
    "fileName": "Contrato de Prestacao de Servicos.pdf",
    "filePath": "templates/company-123/pdf-001.pdf",
    "fileSize": 524288,
    "uploadedAt": "2024-03-20T14:30:00.000Z"
  },
  {
    "id": "pdf-002",
    "fileName": "Modelo NDA Padrao.pdf",
    "filePath": "templates/company-123/pdf-002.pdf",
    "fileSize": 256000,
    "uploadedAt": "2024-03-18T10:15:00.000Z"
  }
]

Ordenação:

Os resultados são retornados ordenados por uploadedAt em ordem decrescente (mais recentes primeiro).

Uso no Frontend:

O usuário pode selecionar um PDF da lista de uploads recentes ao invés de fazer um novo upload. Isso:

  • Evita duplicação de arquivos no storage
  • Acelera o processo de criação de templates
  • Permite reutilizar PDFs base já enviados

Upload de PDF

EndpointMétodoDescrição
/templates/upload-pdfPOSTFaz upload de PDF para S3 e retorna path

Request:

Content-Type: multipart/form-data

file: <arquivo PDF> (máx. 2MB)
fileName: <nome do arquivo definido pelo usuário>

Response:

typescript
type UploadPdfResponse = {
  fileId: string      // UUID do arquivo no storage
  filePath: string    // Caminho: templates/{companyId}/{uuid}.pdf
  fileName: string    // Nome do arquivo definido pelo usuário
}

Nota: O store mapeia fileIdpdfId e filePathpdfPath para uso no payload do template.

Validações (Frontend):

ValidaçãoRegra
FormatoApenas application/pdf
TamanhoMáximo 2MB (2 * 1024 * 1024 bytes)

Criação de Template

Após o upload do PDF, usa-se o pdfId retornado (mapeado de fileId) no payload do POST /templates:

Request POST /templates:

typescript
type CreateTemplatePayload = {
  name: string              // obrigatório
  description?: string      // opcional
  pdfId: string             // obrigatório (mapeado de fileId do upload-pdf)
  variables?: object        // opcional (JSON)
  status?: TemplateStatus   // opcional: 'draft' | 'published' | 'archived'
}

Request PUT /templates/🆔

typescript
type UpdateTemplatePayload = Partial<CreateTemplatePayload> & {
  id: string                // ID do template a atualizar
}

Fluxo Completo:

PdfUploader.vue

Usuário seleciona arquivo PDF

Valida formato e tamanho (frontend)

Abre modal para definir nome do arquivo

Usuário clica em "Iniciar"

uploadTemplatePdfService(file, fileName)

POST /templates/upload-pdf (multipart/form-data)
  - file: arquivo PDF
  - fileName: nome definido pelo usuário

Backend:
  - Faz upload do PDF para S3
  - Retorna { fileId, filePath, fileName }

Store atualiza (mapeia campos):
  - pdfId = response.fileId
  - pdfPath = response.filePath
  - currentStep = 'editing'

Usuário preenche nome, descrição, variáveis

createTemplateService(payload)

POST /templates
  - payload: { name, description, pdfId, variables, status }

Backend:
  - Cria template com status 'draft' (default)
  - Retorna template completo

Signature Ghosts (novo)

O template agora declara ghosts: slots lógicos de assinatura posicionados sobre o documento. Cada ghost tem:

  • label: rótulo escolhido pelo criador (ex: "Diretor Financeiro", "Prestador principal")
  • isProvider: true → resolve dinamicamente para o(s) prestador do contrato; false → atribuído a um usuário da empresa tomadora na criação do contrato
  • placements: 1..N posições no documento (página, x, y, width, height, tipo signature/initials)

Publicação do template exige ao menos 1 ghost provider com placement e 1 ghost não-provider com placement. Em draft pode salvar vazio.

Workflow é template-agnostic: a atribuição ghost→usuário acontece no fluxo de criação do contrato. O workflow não tem mais nada relacionado a posicionamento ou grupos de assinatura.

Types do Módulo Templates

typescript
// src/modules/templates/models/template.type.ts

interface Template {
  id?: string
  name: string
  description?: string
  content: string
  variables: TemplateVariable[]
  ghosts: TemplateSignatureGhost[]
  status: TemplateStatus
  createdAt?: Date
  updatedAt?: Date
}

interface TemplateSignatureGhost {
  id: string
  label: string
  isProvider: boolean
  order: number
  placements: TemplateSignaturePlacement[]
}

interface TemplateSignaturePlacement {
  id: string
  ghostId: string
  page: number
  x: number
  y: number
  width: number
  height: number
  type: 'SIGNATURE' | 'INITIALS'
}

interface TemplateVariable {
  id: string
  name: string
  type: VariableType  // 'text' | 'date' | 'number'
  required: boolean
}

interface UploadPdfResponse {
  pdfId: string
  pdfPath: string
}

interface CreateTemplatePayload {
  name: string
  description?: string
  pdfId: string
  pdfPath: string
  variables?: object
  status?: TemplateStatus
}

interface UpdateTemplatePayload extends CreateTemplatePayload {
  id: string
}

type TemplateStatus = 'draft' | 'published' | 'archived'
type VariableType = 'text' | 'date' | 'number'

Services do Módulo Templates

typescript
// src/modules/templates/services/templates.ts

// CRUD
getTemplatesService(params?: Partial<TemplateFilter>)
getTemplateByIdService(id: string)
createTemplateService(payload: CreateTemplatePayload)
updateTemplateService({ id, ...payload }: UpdateTemplatePayload)
deleteTemplateService(id: string)

// Upload
uploadTemplatePdfService(file: File, fileName: string)

// PDFs Recentes
getRecentPdfsService(search?: string)

Store do Editor de Templates

typescript
// src/modules/templates/stores/templateEditor.ts

// Estado
currentStep: 'upload' | 'editing'
isLoading, isSaving, isUploading: boolean
templateId, templateName, templateDescription: string
templateStatus: TemplateStatus
templateVariables: TemplateVariable[]
pdfFile: File | null
pdfUrl: string      // URL local (blob)
pdfId: string       // UUID do arquivo no storage
pdfPath: string     // Caminho no S3: templates/{companyId}/{uuid}.pdf
totalPages: number
variableMappings: VariableMapping[]

// Métodos principais
uploadPdf(file: File, fileName: string)  // Faz upload e guarda pdfId/pdfPath
useExistingPdf(fileId, filePath, fileName) // Usa PDF já existente (sem upload)
createTemplate()          // Cria template com pdfId/pdfPath
saveTemplate()            // Salva alterações
publishTemplate()         // Publica o template
reset()                   // Limpa o estado

Mocks de Templates

Os dados mockados estão em src/mocks/data.json na coleção templates.

IMPORTANTE: O endpoint POST /templates/upload-pdf não é suportado pelo JSON Server pois requer upload de arquivos. Para desenvolvimento local com mocks, o backend real deve estar rodando ou deve-se criar um middleware customizado.