Skip to content

Data & APIs - Regras de Dados

Nenhum Dado Hardcoded

IMPORTANTE: Dados NUNCA devem ser hardcoded na aplicação. Toda informação exibida deve vir de APIs.

RegraDescrição
Sem dados estáticosNenhum dado de negócio deve ser definido diretamente no código
APIs obrigatóriasToda listagem, filtro ou visualização deve consumir dados de uma API
Mocks obrigatóriosAo criar novas features, sempre criar os mocks correspondentes
Services obrigatóriosToda chamada de API deve passar por um service no módulo correspondente
IDs são UUIDsTodos os IDs devem usar formato UUID

Estrutura de Mocks (MSW)

O projeto usa MSW (Mock Service Worker) para interceptar requisições HTTP durante desenvolvimento.

src/mocks/
├── data/                    # Dados mockados
│   ├── templates.ts         # Templates e PDFs recentes
│   ├── workflows.ts         # Workflows com configurações
│   └── ...
├── handlers/                # Handlers MSW por módulo
│   ├── templates.ts         # Handlers de templates
│   ├── workflows.ts         # Handlers de workflows
│   └── index.ts             # Exporta todos os handlers
├── browser.ts               # Setup para browser
└── server.ts                # Setup para Node/SSR

Workflows API

Endpoints

MétodoEndpointDescrição
GET/workflowsLista workflows (com filtros)
GET/workflows/:idBusca workflow por ID
POST/workflowsCria novo workflow
PUT/workflows/:idAtualiza workflow
DELETE/workflows/:idRemove workflow

Estrutura do Workflow

typescript
interface Workflow {
  id: string // UUID
  name: string
  description?: string
  status: 'draft' | 'published'
  steps: WorkflowStep[]
  documentsConfig?: DocumentRequirement[]
  modelConfig?: ModelStepConfig
  revisionConfig?: RevisionStepConfig
  signatureConfig?: SignatureStepConfig
  createdAt: Date
  updatedAt: Date
}

WorkflowStep

typescript
interface WorkflowStep {
  id: string // UUID
  key: StepKey // 'parts' | 'model' | 'documents' | 'revision' | 'upload' | 'signature'
  name: string
  order: number
  parentId: string
  isEnabled: boolean
  isRequired: boolean
  properties: StepProperty[]
}

Steps e Posições Fixas

StepKeyPosiçãoObrigatório
PartespartsPrimeiro (fixo)Sim
ModelomodelSegundo (fixo)Sim
DocumentosdocumentsMóvelNão
RevisãorevisionMóvelNão
UploaduploadAuto-gerenciadoNão
AssinaturasignatureÚltimo (fixo)Sim

Step Properties

Cada step pode ter propriedades configuráveis:

typescript
interface StepProperty {
  key: string
  label: string // Chave i18n
  type: 'boolean' | 'number' | 'text' | 'select'
  value: boolean | string | number
  options?: StepPropertyOption[] // Para type='select'
}

Propriedades por Step:

  • Model: requirePreviousCompletion, allowCustomTemplate, defaultTemplateId
  • Documents: requirePreviousCompletion, requiredDocuments, allowOptional
  • Revision: requirePreviousCompletion, minReviewers, requireApproval
  • Upload: requirePreviousCompletion, overdueDays, maxFileSize, allowedFormats
  • Signature: requirePreviousCompletion, overdueDays, signatureType, requireOrder

DocumentRequirement

typescript
interface DocumentRequirement {
  id: string
  name: string
  description?: string
  isRequired: boolean
  isDownload: boolean // true = documento para download
  downloadFile?: DocumentFile // Arquivo para download (quando isDownload=true)
  acceptedFormats: string[] // ['pdf', 'jpg', 'png']
  maxFileSize: number // Em MB
}

interface DocumentFile {
  fileName: string
  fileId: string
  fileUrl?: string
}

ModelStepConfig

typescript
interface ModelStepConfig {
  templateId: string // UUID do template
  partGroups: PartGroup[]
  variableAssignments: VariableAssignment[]
}

interface PartGroup {
  id: string
  name: string
  members: PartGroupMember[]
}

interface VariableAssignment {
  variableName: string
  sourceType: 'part_field' | 'predefined'
  partGroupId?: string
  partField?: PartFieldKey // 'name' | 'email' | 'document' | 'phone' | 'cnpj' | 'razao_social' | 'cpf'
  predefinedValue?: string
}

RevisionStepConfig

typescript
interface RevisionStepConfig {
  reviewers: ReviewerMember[]
}

interface ReviewerMember {
  id: string
  userId: string
  name: string
  email: string
  avatar?: string
  isRequired: boolean
  order: number
}

SignatureStepConfig

typescript
interface SignatureStepConfig {
  groups: SignatureGroup[]
  signatureOrder: 'internal_first' | 'parts_first' | 'simultaneous'
}

interface SignatureGroup {
  id: string
  name: string
  type: 'internal' | 'parts' | 'witness'
  order: number
  isFixed: boolean
  members: SignerMember[]
}

interface SignerMember {
  id: string
  userId?: string
  name: string
  email: string
  order: number
}

Templates API

Endpoints

MétodoEndpointDescrição
GET/templatesLista templates (com filtros)
GET/templates/:idBusca template por ID
POST/templatesCria novo template
PUT/templates/:idAtualiza template
DELETE/templates/:idRemove template
PATCH/templates/:id/statusAltera status
POST/templates/:id/duplicateDuplica template
POST/templates/upload-pdfUpload de PDF
GET/templates/recent-pdfsLista PDFs recentes

Estrutura do Template

typescript
interface Template {
  id: string // UUID
  name: string
  description?: string
  content: string // HTML do template
  pdfPath?: string // Caminho do PDF
  variables: TemplateVariable[]
  variablesMapping?: VariableMapping[] // Mapeamento de variáveis no PDF
  status: 'draft' | 'published' | 'archived'
  createdAt: Date
  updatedAt: Date
}

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

interface VariableMapping {
  name: string // Nome da variável
  originalText: string // Texto original no PDF
  page: number // Página do PDF
  position: {
    start: number
    end: number
  }
  normalizedPosition?: NormalizedPosition // Posição visual no PDF
}

interface NormalizedPosition {
  xPercent: number // Posição X em porcentagem
  yPercent: number // Posição Y em porcentagem
  widthPercent: number // Largura em porcentagem
  heightPercent: number // Altura em porcentagem
}

Monitoring API

API para monitoramento de horas trabalhadas pelos prestadores (providers).

Endpoints

MétodoEndpointDescrição
GET/monitoring/Lista providers com resumo de horas
GET/monitoring/:idDetalhes de um provider (com summaries)
GET/monitoring/:id/entriesLista entradas de trabalho de um provider
GET/monitoring/entries/:idBusca entrada específica
POST/monitoring/entriesCria nova entrada de trabalho
PUT/monitoring/entries/:idAtualiza entrada
DELETE/monitoring/entries/:idRemove entrada

Query Parameters

GET /monitoring/

  • search: string - Busca por nome da empresa ou contrato
  • status: 'active' | 'inactive' | 'all' - Filtro por status

GET /monitoring/:id/entries

  • startDate: string (ISO date) - Data inicial
  • endDate: string (ISO date) - Data final

Estrutura ProviderWithHours

typescript
interface ProviderWithHours {
  id: string // UUID
  companyId: string
  companyName: string
  contractId: string
  contractName: string
  totalHoursMonth: number
  totalHoursWeek: number
  lastEntry?: Date
  status: 'active' | 'inactive'
}

Estrutura ProviderHoursDetail

Retornado pelo endpoint GET /monitoring/:id:

typescript
interface ProviderHoursDetail {
  provider: ProviderWithHours
  dailySummary: DailySummary[]
  weeklySummary: WeeklySummary
  monthlySummary: MonthlySummary
}

interface DailySummary {
  date: Date
  totalMinutes: number
  entries: WorkEntry[]
}

interface WeeklySummary {
  weekStart: Date
  weekEnd: Date
  totalMinutes: number
  dailyTotals: { date: Date; minutes: number }[]
}

interface MonthlySummary {
  month: number
  year: number
  totalMinutes: number
  weeklyTotals: { weekNumber: number; minutes: number }[]
}

Estrutura WorkEntry

typescript
interface WorkEntry {
  id: string // UUID
  providerId: string // UUID do provider
  date: Date
  startTime: string // Formato "HH:mm"
  endTime: string // Formato "HH:mm"
  totalMinutes: number
  description: string
  reason?: string
  tasks: WorkTask[]
  createdAt: Date
  updatedAt: Date
}

interface WorkTask {
  id: string
  description: string
  durationMinutes: number
}

Payloads de entrada

typescript
// POST /monitoring/entries - Criar nova entrada
interface CreateWorkEntryPayload {
  providerId: string // Obrigatório no POST
  date: Date
  startTime: string // Formato "HH:mm"
  endTime: string // Formato "HH:mm"
  description: string
  reason?: string
  tasks: { description: string; durationMinutes: number }[]
}

// PUT /monitoring/entries/:id - Atualizar entrada existente
// Nota: providerId NÃO é enviado no PUT (já está associado à entry)
interface UpdateWorkEntryPayload {
  date?: Date
  startTime?: string // Formato "HH:mm"
  endTime?: string // Formato "HH:mm"
  description?: string
  reason?: string
  tasks?: { description: string; durationMinutes: number }[]
}

Reports API

API para geração de relatórios de horas dos prestadores.

Endpoints

MétodoEndpointDescrição
GET/reportsLista relatórios
GET/reports/:idBusca relatório por ID
POST/reportsCria novo relatório
DELETE/reports/:idRemove relatório
GET/reports/:id/downloadDownload do arquivo

Estrutura Report

typescript
interface Report {
  id: string // UUID
  name: string
  type: 'daily' | 'weekly' | 'monthly'
  status: 'pending' | 'processing' | 'completed' | 'failed'
  providerIds: string[] // UUIDs dos providers
  providersCount: number
  fileUrl?: string
  fileSize?: number
  fileFormat?: 'csv' | 'xls' | 'xlsx' | 'zip' | 'pdf'
  requestedBy: string
  createdAt: Date
  updatedAt: Date
  completedAt?: Date
  errorMessage?: string
}

Payload para criar relatório

typescript
interface CreateReportPayload {
  name: string
  type: 'daily' | 'weekly' | 'monthly'
  providerIds: string[] // UUIDs dos providers
}

Profile API

API para gerenciamento do perfil do usuário autenticado.

Endpoints

MétodoEndpointDescrição
GET/users/meRetorna dados do usuário autenticado
PUT/users/meAtualiza dados do perfil
PUT/users/me/passwordAltera a senha do usuário
POST/users/me/register-passwordCadastra senha (provider email)
POST/users/me/connect-providerConecta um provider OAuth à conta

GET /users/me

Retorna o usuário autenticado, empresas associadas e histórico de sessões.

Response:

typescript
type CurrentUserResponse = {
  user: User
  companies: Company[]
  sessions: SessionEntry[]
}

type User = {
  id: string
  email: string
  name: string
  avatar?: string
  providers: string[] // Array de providers conectados (ex: ['google', 'linkedin', 'email'])
  phone?: string
  cpf?: string
  emailVerified?: boolean // Se o email foi verificado
  phoneVerified?: boolean // Se o telefone foi verificado
}

type SessionEntry = {
  id: string
  browser: string // Ex: "Chrome 120"
  os: string // Ex: "Windows 11"
  ip: string // Ex: "189.44.120.33"
  createdAt: string // ISO date string
}

Nota: O campo providers substituiu o antigo provider: AuthProvider (singular). Agora é um array de strings com todos os providers conectados à conta do usuário. O campo active (status do usuário) não faz parte da chave user.

PUT /users/me

Atualiza o perfil do usuário autenticado.

Request:

typescript
type UpdateProfilePayload = {
  name: string // Obrigatório
  phone?: string // Apenas dígitos
  cpf?: string // Apenas dígitos
}

Response: User atualizado.

PUT /users/me/password

Altera a senha do usuário autenticado. Requer que o provider email já esteja conectado.

Request:

typescript
type ChangePasswordPayload = {
  currentPassword: string // Senha atual (mínimo 6 caracteres)
  newPassword: string // Nova senha (mínimo 8 caracteres)
}

Response: { success: true }

Erros:

StatusDescrição
400Senha atual inválida
401Não autenticado

POST /users/me/register-password

Cadastra uma senha para o usuário (adiciona o provider email). Usado quando o usuário ainda não possui login via email/senha.

Request:

typescript
type RegisterPasswordPayload = {
  password: string // Nova senha (mínimo 8 caracteres)
  confirmPassword: string // Confirmação da senha
}

Response: { success: true }

Efeito: Adiciona 'email' ao array providers do usuário.

Erros:

StatusDescrição
400Senha muito curta ou senhas não coincidem
401Não autenticado

POST /users/me/connect-provider

Conecta um provider OAuth à conta do usuário. O email retornado pelo provider deve ser o mesmo email da conta logada.

Request:

typescript
type ConnectProviderPayload = {
  provider: AuthProvider // 'google' | 'linkedin' | 'microsoft' | 'github'
  code: string // Código OAuth retornado pelo provider
}

Response: User atualizado (com o novo provider no array providers).

Erros:

StatusDescrição
400Email do provider não corresponde ao email da conta
401Não autenticado

Compliance API

API para criação e gerenciamento de fluxos de compliance dinâmicos.

Endpoints

MétodoEndpointDescrição
GET/compliance-flowsLista fluxos (com filtros: search, status)
GET/compliance-flows/:idBusca fluxo por ID
POST/compliance-flowsCria novo fluxo
PUT/compliance-flows/:idAtualiza fluxo
DELETE/compliance-flows/:idRemove fluxo

Estrutura ComplianceFlow

typescript
interface ComplianceFlow {
  id: string
  name: string
  description?: string
  status: 'draft' | 'active' | 'archived'
  steps: ComplianceStep[]
  createdAt: Date
  updatedAt: Date
}

ComplianceStep

typescript
interface ComplianceStep {
  id: string
  title: string
  order: number
  schedule: StepSchedule
  documents: ComplianceDocumentRequirement[]
  validators: ComplianceValidator[]
  dependsOnPrevious: boolean
  includeImmediateLeadership: boolean
  onlyImmediateLeadershipRequired: boolean
  allValidatorsRequired: boolean
}

Regras dos checkboxes de validação

  • onlyImmediateLeadershipRequired fica desabilitado quando includeImmediateLeadership é false
  • Quando includeImmediateLeadership é desmarcado, onlyImmediateLeadershipRequired volta para false
  • Quando allValidatorsRequired é marcado e includeImmediateLeadership está marcado, onlyImmediateLeadershipRequired é forçado para true e desabilitado

Payloads

typescript
interface CreateComplianceFlowPayload {
  name: string
  description?: string
  steps: CreateComplianceStepPayload[]
}

interface CreateComplianceStepPayload {
  title: string
  order: number
  schedule: StepSchedule
  documents: Omit<ComplianceDocumentRequirement, 'id'>[]
  validators: string[] // User IDs
  dependsOnPrevious: boolean
  includeImmediateLeadership: boolean
  onlyImmediateLeadershipRequired: boolean
  allValidatorsRequired: boolean
}

Ao criar uma nova feature

  1. Criar os tipos no domain: src/domain/[modulo]/types.ts
  2. Criar constantes se necessário: src/domain/[modulo]/constants.ts
  3. Criar dados mockados: src/mocks/data/[modulo].ts
  4. Criar handlers MSW: src/mocks/handlers/[modulo].ts
  5. Registrar handlers em: src/mocks/handlers/index.ts
  6. Criar service: src/modules/[modulo]/services/[modulo].ts
  7. Consumir via store ou composable

Regras de IDs

  • Todos os IDs devem ser UUIDs no formato: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
  • IDs de steps seguem o padrão: step-{key}-{timestamp}-{index}
  • IDs de grupos seguem o padrão: group-{timestamp} ou UUID