Pular para conteúdo

CoreModule

O CoreModule é o núcleo da camada de API da soulsys plataforma. Ele reúne todos os recursos essenciais que sustentam o funcionamento da plataforma — autenticação, autorização, internacionalização, cache, geração de documentos, armazenamento de arquivos e utilitários compartilhados entre os demais módulos.

Por ser um módulo global (@Global()), o CoreModule pode ser importado uma única vez e seus serviços passam a estar disponíveis em toda a aplicação, garantindo padronização, reuso e simplicidade na criação de novas funcionalidades.

Além disso, ele exporta seus submódulos para projetos externos que utilizam @soulsys/api, permitindo que integrações, módulos complementares e soluções personalizadas aproveitem a mesma infraestrutura e boas práticas da plataforma.

Como Inicializar

Para iniciar uma aplicação utilizando os padrões da plataforma, importe o CoreModule no módulo raiz e utilize o helper bootstrap, responsável por configurar prefixos globais, CORS, validações, logger e o redirecionamento automático para HTTPS (quando habilitado).

import { Module } from "@nestjs/common"
import { CoreModule, bootstrap } from "@soulsys/api/core"

@Module({
  imports: [CoreModule],
})
export class AppModule {}

// main.ts
bootstrap(AppModule)

Guardas Globais

Os guardas são registrados como APP_GUARD e funcionam em cascata.

  • AuthGuard: valida Bearer token (Authorization) ou authToken via query string. Aceita token de usuário e token de sistema. Use @Public() para rotas que não exigem autenticação.
  • CompanyGuard: lê o header syscompany (id da empresa) e garante que o usuário pertence à empresa antes de colocá-la no contexto.
  • RolesGuard: exige papéis informados em @Roles(...). Use a constante SYS_ADMIN_ROLE para rotas administrativas.
  • I18NGuard: define o locale a partir de sys_locale (query/body) e inicializa numeral/dayjs.
  • LoggerGuard: habilitado somente quando REQUEST_LOGGER=true; registra método, rota, status e tempo de resposta.

Contexto de Requisição

O ContextService guarda informações resolvidas pelos guardas.

import { Controller, Get } from "@nestjs/common"
import { ContextService } from "@soulsys/api/core"

@Controller("sales")
export class SalesController {
  constructor(private ctx: ContextService) {}

  @Get("current-context")
  getContext() {
    return {
      user: this.ctx.user,
      company: this.ctx.company,
    }
  }
}

Autenticação

O AuthModule oferece fluxo completo de login com ou sem OTP, recuperação de senha, convite e renovação de tokens.

  • POST /api/sys/auth/login: autentica com email e password. Se AUTH_OTP=true, retorna otp=true e envia código por e-mail; caso contrário já devolve user, accessToken e refreshToken.
  • POST /api/sys/auth/otp: finaliza login com accessToken temporário e otp, retornando novos tokens.
  • POST /api/sys/auth/refresh-access-token: gera novo access token a partir do refreshToken.
  • POST /api/sys/auth/password-recovery: envia link de redefinição usando AUTH_PSW_UPDATE_URL.
  • POST /api/sys/auth/user-invite: reenvia link de convite (token de redefinição).
  • POST /api/sys/auth/check-password e POST /api/sys/auth/update-password: validam e aplicam a política de senha.
  • GET /api/sys/auth/psw-policy: expõe a política configurada.

Exemplo de login com OTP habilitado:

POST /api/sys/auth/login
Content-Type: application/json
{
  "email": "admin@soulsys.tech",
  "password": "senhaSegura123"
}
// resposta
{
  "otp": true,
  "accessToken": "<token-temporario>"
}

POST /api/sys/auth/otp
{
  "accessToken": "<token-temporario>",
  "otp": "123456"
}
// resposta final
{
  "user": { "...": "dados" },
  "accessToken": "<jwt>",
  "refreshToken": "<jwt>"
}

Tokens de sistema podem ser gerados via POST /api/sys/users/token (restrito a SYS_ADMIN_ROLE) para integrações server-to-server usando clientId e clientSecret.

Usuários

CRUD completo de usuários, associação a papéis e empresas e geração de tokens de sistema.

  • POST /api/sys/users (admin): cria usuários do tipo person ou system.
  • POST /api/sys/users/find (admin): paginação e filtros.
  • GET /api/sys/users/:id: retorna usuário; :id = whoami traz o usuário autenticado.
  • POST /api/sys/users/update-profile: atualiza nome do usuário logado.
  • POST /api/sys/users/token (admin): gera token de sistema com clientId e clientSecret.

Exemplo de geração de token de sistema:

POST /api/sys/users/token
Authorization: Bearer <access-token-admin>
{
  "clientId": "my-system",
  "clientSecret": "super-secret"
}
// resposta
{ "token": "<jwt-de-sistema>" }

Papéis

  • POST /api/sys/roles (admin): cria papéis com code e description.
  • POST /api/sys/roles/find (admin): lista paginada.
  • PATCH /api/sys/roles/:id e DELETE /api/sys/roles/:id: manutenção de papéis.

Use @Roles("meu_papel") para proteger rotas. A constante SYS_ADMIN_ROLE representa o papel administrador padrão criado no seed.

Empresas

  • POST /api/sys/companies (admin): cria empresa com dados cadastrais.
  • POST /api/sys/companies/find (admin): filtros por name, shortName, city, cnpj.
  • GET /api/sys/companies/:id/can-delete: verifica se há usuários associados.
  • Defina o cabeçalho syscompany: <companyId> para vincular a requisição a uma empresa específica.

Internacionalização

O I18NService controla locale e formatos numéricos/data. Locale aceito: pt-br, en, es-us via sys_locale.

import { Controller, Get, Query } from "@nestjs/common"
import { I18NService, SYS_LOCALE } from "@soulsys/api/core"

@Controller("reports")
export class ReportController {
  constructor(private i18n: I18NService) {}

  @Get("totals")
  totals(@Query("value") value: number, @Query("date") date: string) {
    return {
      currency: this.i18n.formatCurrency(value),
      date: this.i18n.formatDate(date),
    }
  }
}

Assets

O AssetService resolve caminhos para templates internos e busca assets do web client, com cache em memória.

import { Controller, Get } from "@nestjs/common"
import { AssetService, assetPath } from "@soulsys/api/core"

@Controller("assets-demo")
export class AssetsDemoController {
  constructor(private assets: AssetService) {}

  @Get("template-path")
  path() {
    return assetPath("core/assets/templates/auth/otp/otp.pt-br.html")
  }

  @Get("web-logo")
  async logo() {
    const data = await this.assets.fetchFromWebClient("images/logo.png")
    return { size: (data as ArrayBuffer).byteLength }
  }
}

E-mail

Envio via SMTP com Handlebars. Prefixa assunto com APP_NAME e permite desabilitar envios com SMTP_DISABLED.

import { Controller, Post, Body } from "@nestjs/common"
import { EmailService } from "@soulsys/api/core"

@Controller("notifications")
export class NotificationsController {
  constructor(private email: EmailService) {}

  @Post("welcome")
  async sendWelcome(@Body("to") to: string) {
    await this.email.send({
      to,
      subject: "Bem-vindo",
      template: {
        path: "core/assets/templates/auth/invitation/invitation.pt-br.html",
        data: { appName: "Minha App", companyName: "Empresa" },
      },
    })
    return { sent: true }
  }
}

PDF

Construtor baseado em pdfkit que usa cor primária (WEB_CLIENT_PRIMARY_COLOR) e logo do web client.

import { Controller, Get, Res } from "@nestjs/common"
import { Response } from "express"
import { PdfService } from "@soulsys/api/core"

@Controller("docs")
export class DocsController {
  constructor(private pdf: PdfService) {}

  @Get("invoice")
  async invoice(@Res() res: Response) {
    const sysPdf = await this.pdf.createInstance().init({ hasFooter: true })
    sysPdf.regularFont().text("Fatura #123", { align: "left" })
    sysPdf.doc.end()

    res.setHeader("Content-Type", "application/pdf")
    sysPdf.doc.pipe(res)
  }
}

Excel

Leitura e escrita de planilhas (write-excel-file e read-excel-file). Trabalha com Buffer ou base64.

import { Controller, Get, Post, Body } from "@nestjs/common"
import { ExcelService } from "@soulsys/api/core"

@Controller("excel")
export class ExcelController {
  constructor(private excel: ExcelService) {}

  @Get("sample")
  async sample() {
    const buffer = await this.excel.create([
      [
        { value: "Nome", fontWeight: "bold" },
        { value: "Email", fontWeight: "bold" },
      ],
      [{ value: "Alice" }, { value: "alice@soulsys.tech" }],
    ])
    return { fileBase64: buffer.toString("base64") }
  }

  @Post("read")
  async read(@Body("fileBase64") fileBase64: string) {
    const rows = await this.excel.read({ fileAsBase64: fileBase64 })
    return { rows }
  }
}

Storage

Upload e download de arquivos binários via API. Os dados são persistidos no banco (tabela storage).

  • POST /api/sys/storage/upload (multipart, campo file): retorna metadata e URL de download.
  • GET /api/sys/storage/:id: metadata com URL.
  • GET /api/sys/storage/:id/download: conteúdo do arquivo.
  • DELETE /api/sys/storage/:id: remove o arquivo.

Exemplo de upload (cURL):

curl -X POST http://localhost:3000/api/sys/storage/upload \
  -H "Authorization: Bearer <token>" \
  -F "file=@/caminho/arquivo.pdf"

Pontos de Entrada

Permite registrar callbacks por evento e invocá-los dinamicamente.

import { Injectable } from "@nestjs/common"
import { EntryPoint, EntryPointService } from "@soulsys/api/core"

@Injectable()
export class IntegrationListener {
  @EntryPoint("customer.created")
  onCustomerCreated(payload: any) {
    // lógica customizada
  }
}

// Em outro serviço
await this.entryPointService.discoverProviders()
await this.entryPointService.call("customer.created", { id: "123" })

HTTP

Classe base para padronizar integrações HTTP externas. Sobrescreva getApiUrl e getHeaders.

import { Injectable } from "@nestjs/common"
import { HttpService } from "@soulsys/api/core"

@Injectable()
export class CrmHttp extends HttpService {
  async getHeaders() {
    return {
      Authorization: "Bearer " + process.env.CRM_TOKEN,
    }
  }

  async getApiUrl(path: string) {
    return `https://crm.example.com${path}`
  }
}

// Uso
await this.crmHttp.post("/contacts", { name: "Cliente" })

Socket

SocketGateway inicializa o socket.io com CORS liberado e expõe o server em SocketService para emitir eventos.

import { Injectable } from "@nestjs/common"
import { SocketService } from "@soulsys/api/core"

@Injectable()
export class NotificationsEmitter {
  constructor(private socket: SocketService) {}

  notifyAll(event: string, data: any) {
    this.socket.server?.emit(event, data)
  }
}

Logger

LoggerService herda de @nestjs/common e prefixa logs com APP_NAME e versão (npm_package_version). O LoggerGuard pode registrar requisições automaticamente quando REQUEST_LOGGER=true.

Variáveis de Ambiente

Defina todas as variáveis no arquivo _plataforma/api/.env_.

Servidor

Variável Descrição
DEV_ENV Ajusta comportamentos de desenvolvimento (ex.: limites de throttling).
PORT Porta HTTP da API.
APP_NAME Nome exibido em logs e e-mails.
COMPANY_NAME Empresa responsável (usada em templates).
REQUEST_LOGGER Ativa o LoggerGuard para registrar cada requisição.
ENSURE_HTTPS Redireciona HTTP para HTTPS usando express-sslify.

Banco de dados

Variável Descrição
DATABASE_URL String de conexão utilizada pelo Prisma.

Autenticação

Variável Descrição
AUTH_OTP Habilita a etapa de OTP no login.
AUTH_ACCESS_TOKEN_MINUTES Validade (minutos) do access token.
AUTH_REFRESH_TOKEN_DAYS Validade (dias) do refresh token.
AUTH_PSW_MIN_LENGTH Tamanho mínimo da senha.
AUTH_PSW_CHANGE_AFTER_DAYS Dias para expiração da senha.
AUTH_PSW_MIXED_CHARS Exige mistura de maiúsculas, minúsculas e caracteres especiais.
AUTH_PSW_UPDATE_URL URL da página de redefinição de senha utilizada em e-mails.
AUTH_ROOT_EMAIL E-mail do usuário admin criado no seed inicial.
AUTH_JWT_SECRET Chave usada para assinar tokens JWT.

Web Client

Variável Descrição
WEB_CLIENT_ASSETS_URL URL base dos assets do frontend (usada para logo e templates).
WEB_CLIENT_PRIMARY_COLOR Cor primária aplicada em PDFs e templates.
WEB_CLIENT_PRIMARY_COLOR_HOVER Cor de hover complementar.

SMTP

Variável Descrição
SMTP_SERVER Host SMTP.
SMTP_PORT Porta SMTP.
SMTP_SECURE Se true, força TLS/SSL.
SMTP_LOGIN Usuário de autenticação.
SMTP_PASSWORD Senha ou token de autenticação.
SMTP_FROM Remetente padrão dos e-mails.
SMTP_DISABLED Desativa envios (útil para ambientes de teste).

Com o CoreModule configurado, os demais módulos da plataforma podem focar apenas nas regras de negócio, reutilizando autenticação, armazenamento, internacionalização e utilitários já padronizados.