Backoffice API - NestJS

GoHorse Jobs SaaS Administration, Subscription Management, and Email Worker API.
🏗️ Arquitetura
C4Container
title Container Diagram - Backoffice Architecture
Person(admin, "Admin System", "Platform Administrator")
System_Ext(go_api, "Go Backend API", "Core Business Logic")
Container_Boundary(backoffice_boundary, "Backoffice") {
Container(backoffice, "Backoffice API", "NestJS", "Admin Dashboard, Worker & Integration Layer")
}
System_Ext(db, "PostgreSQL", "Shared Database (Templates, Settings)")
System_Ext(mq, "LavinMQ", "Email/Job Queue")
System_Ext(stripe, "Stripe", "Payment Gateway")
System_Ext(fcm, "Firebase FCM", "Push Notifications")
System_Ext(smtp, "SMTP Service", "Email Delivery")
Rel(admin, backoffice, "Views Stats/Revenue", "HTTPS")
Rel(go_api, mq, "Publishes Email Jobs", "AMQP")
Rel(backoffice, mq, "Consumes Jobs", "AMQP")
Rel(backoffice, db, "Read/Write", "SQL")
Rel(backoffice, stripe, "Syncs Payments", "HTTPS")
Rel(backoffice, fcm, "Sends Notifications", "HTTPS")
Rel(backoffice, smtp, "Sends Emails", "SMTP")
backoffice/
├── src/
│ ├── admin/ # Dashboard e estatísticas
│ │ ├── admin.controller.ts
│ │ ├── admin.service.ts
│ │ └── admin.module.ts
│ │
│ ├── auth/ # Autenticação JWT
│ │ ├── jwt-auth.guard.ts
│ │ ├── jwt-strategy.ts
│ │ └── auth.module.ts
│ │
│ ├── email/ # Email Worker (LavinMQ Consumer)
│ │ ├── email.service.ts
│ │ ├── email.module.ts
│ │ └── entities/
│ │ ├── email-setting.entity.ts
│ │ └── email-template.entity.ts
│ │
│ ├── external-services/ # Gestão de credenciais
│ │ ├── external-services.controller.ts
│ │ ├── external-services.service.ts
│ │ └── external-services.module.ts
│ │
│ ├── fcm-tokens/ # Firebase Cloud Messaging
│ │ ├── fcm-tokens.controller.ts
│ │ ├── fcm-tokens.service.ts
│ │ └── fcm-tokens.module.ts
│ │
│ ├── plans/ # Planos de assinatura
│ │ ├── plans.controller.ts
│ │ ├── plans.service.ts
│ │ └── plans.module.ts
│ │
│ ├── stripe/ # Integração Stripe
│ │ ├── stripe.controller.ts
│ │ ├── stripe.service.ts
│ │ └── stripe.module.ts
│ │
│ ├── app.module.ts # Módulo raiz
│ └── main.ts # Bootstrap
🔧 Módulos
| Módulo |
Descrição |
| AdminModule |
Dashboard stats, revenue analytics, subscription metrics |
| AuthModule |
JWT validation (Bearer + Cookie), guards |
| EmailModule |
LavinMQ consumer, Nodemailer sender, template rendering (Handlebars) |
| ExternalServicesModule |
RSA encryption, credentials storage |
| FcmTokensModule |
Firebase Admin SDK, push notifications |
| PlansModule |
Subscription plans CRUD |
| StripeModule |
Checkout sessions, webhooks, billing portal |
📧 Email Worker
O módulo EmailModule atua como consumer do LavinMQ:
Fluxo
1. Go Backend → Publica job em `mail_queue`
2. NestJS → Consome job da fila
3. NestJS → Busca template do banco (email_templates)
4. NestJS → Renderiza com Handlebars
5. NestJS → Envia via SMTP (Nodemailer)
Entidades (TypeORM)
// email_settings
{
id: UUID,
provider: string,
smtp_host: string,
smtp_port: number,
smtp_user: string,
smtp_pass: string,
smtp_secure: boolean,
sender_name: string,
sender_email: string,
amqp_url: string,
is_active: boolean
}
// email_templates
{
id: UUID,
slug: string,
subject: string,
body_html: string,
variables: string[]
}
💳 Stripe Integration
Endpoints
| Método |
Endpoint |
Descrição |
POST |
/stripe/checkout |
Criar Checkout Session |
POST |
/stripe/portal |
Criar Billing Portal |
POST |
/stripe/webhook |
Webhook handler |
Webhooks Suportados
checkout.session.completed - Pagamento concluído
customer.subscription.created - Nova assinatura
customer.subscription.updated - Assinatura atualizada
customer.subscription.deleted - Assinatura cancelada
invoice.payment_failed - Pagamento falhou
📊 API Reference (Endpoints)
📈 Dashboard & Analytics (Admin)
| Método |
Endpoint |
Descrição |
GET |
/admin/stats |
Estatísticas gerais (Empresas, Receita, Assinaturas) |
GET |
/admin/revenue |
Receita mensal detalhada |
GET |
/admin/subscriptions-by-plan |
Distribuição de assinaturas por plano |
📦 Plans Management (SaaS)
| Método |
Endpoint |
Descrição |
GET |
/plans |
Listar todos os planos |
GET |
/plans/{id} |
Detalhes de um plano |
POST |
/plans |
Criar novo plano |
PATCH |
/plans/{id} |
Atualizar plano |
DELETE |
/plans/{id} |
Remover plano |
🔑 Credentials & Integrations
| Método |
Endpoint |
Descrição |
POST |
/admin/credentials/stripe |
Salvar Chave API Stripe (Criptografado) |
GET |
/system/credentials |
Listar serviços com credenciais configuradas |
POST |
/system/credentials |
Salvar credencial genérica (Service Payload) |
DELETE |
/system/credentials/{serviceName} |
Remover credencial de serviço |
📲 Push Notifications (FCM)
| Método |
Endpoint |
Descrição |
POST |
/fcm-tokens |
Registrar token de dispositivo (iOS/Android/Web) |
💳 Stripe & Billing
| Método |
Endpoint |
Descrição |
POST |
/stripe/checkout |
Criar Checkout Session |
POST |
/stripe/portal |
Gerar Link do Billing Portal |
POST |
/stripe/webhook |
Webhook Event Handler |
🔒 Autenticação
O backoffice suporta dois métodos:
- Bearer Token -
Authorization: Bearer <token>
- JWT Cookie -
jwt=<token> (fallback)
Implementado em src/auth/jwt-auth.guard.ts.
🔐 External Services Credentials
Gerenciamento seguro de credenciais com criptografia RSA:
// Fluxo de criptografia
1. Frontend envia credencial
2. Backoffice criptografa com RSA public key
3. Armazena criptografada no banco (external_services_credentials)
4. Go Backend descriptografa com private key quando necessário
Services Suportados
- Stripe
- Firebase (FCM)
- Cloudflare
- SMTP (Email)
- S3/R2 (Storage)
🔧 Environment Variables
# Server
PORT=3001
# Database (compartilhado com Go)
DATABASE_URL=postgres://user:pass@host:5432/dbname
# Stripe
STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
# Firebase
FIREBASE_ADMIN_SDK_PATH=/path/to/service-account.json
# OU
FIREBASE_SERVICE_ACCOUNT={"type":"service_account",...}
# JWT (mesmo do Go backend)
JWT_SECRET=your-secret-key
🚀 Desenvolvimento Local
Pré-requisitos
- Node.js 20+
- pnpm 9+
- Podman (para containerizar)
Executar (Nativo)
# Instalar dependências
pnpm install
# Desenvolvimento (Hot Reload)
pnpm start:dev
# Produção
pnpm build
pnpm start:prod
Executar com Podman (Container)
# Build da imagem
podman build -t gohorse-backoffice .
# Rodar container
# --net host recomendado para acessar DB local em desenvolvimento
podman run --name backoffice -p 3001:3001 --env-file .env gohorse-backoffice
Nota: Para orquestração em produção, utilizamos Quadlet.
📦 Tech Stack
| Tecnologia |
Versão |
Uso |
| NestJS |
11+ |
Framework |
| Fastify |
4+ |
HTTP Server |
| TypeORM |
0.3+ |
ORM (Email entities) |
| Stripe |
20+ |
Pagamentos |
| Firebase Admin |
13+ |
Push Notifications |
| amqplib |
0.10+ |
LavinMQ Consumer |
| Nodemailer |
6+ |
SMTP Client |
| Handlebars |
4+ |
Template Engine |
| Pino |
9+ |
Logging |
🔗 Integrações
| Serviço |
Módulo |
Uso |
| Stripe |
StripeModule |
Pagamentos, assinaturas |
| LavinMQ |
EmailModule |
Fila de emails |
| Firebase |
FcmTokensModule |
Push notifications |
| PostgreSQL |
TypeORM |
Email settings/templates |