Data Access Layer para o sistema Canalize PRM
Canalizedb é a camada de acesso a dados do sistema Canalize PRM. Fornece models GORM, repositories, services e migrations para PostgreSQL.
- 📦 Models GORM: Mapeamento ORM para PostgreSQL
- 🗄️ Repositories: Padrão Repository para acesso a dados
- 💼 Services: Lógica de negócio e validações
- 🏭 Factory: Exports públicos e dependency injection
- 🔄 Migrations: Scripts SQL de inicialização
- 🔐 Multi-tenant: Isolamento por
company_id
canalizedb/
├── internal/
│ ├── models/
│ │ ├── prm/ # Partner Relationship Management
│ │ │ ├── partner_model.go # ✅ Partner models
│ │ │ ├── partner_repo.go # ✅ Partner repository
│ │ │ ├── partner_service.go # ✅ Partner service
│ │ │ ├── wizard_models.go # ✅ Wizard models
│ │ │ ├── wizard_service.go # ✅ Wizard service
│ │ │ ├── commission_rule_repo.go
│ │ │ ├── company_repo.go
│ │ │ ├── pipeline_repo.go
│ │ │ └── ...
│ │ ├── clients/ # Clientes/Customers
│ │ ├── oauth/ # OAuth/Auth
│ │ └── notification/ # Notificações
│ ├── bootstrap/
│ │ └── embedded/ # SQL migrations
│ │ ├── 001_init.sql
│ │ ├── 002_hardening.sql
│ │ ├── 003_create_invites.sql
│ │ └── 004_wizard_and_missing_schema.sql
│ └── services/ # Shared services
├── factory/ # Public API
│ ├── partner.go # ✅ Partner exports
│ ├── wizard.go # ✅ Wizard exports
│ └── ...
├── go.mod
└── README.md # This file
- Repository Pattern: Abstração de acesso a dados
- Service Layer: Lógica de negócio separada
- Factory Pattern: Dependency injection e exports públicos
- DTO Pattern: Data Transfer Objects para APIs
# Clone o repositório
git clone https://github.com/canalize-prm/canalizedb.git
cd canalizedb
# Instale dependências
go mod downloadimport (
"github.com/canalize-prm/canalizedb/factory"
"gorm.io/gorm"
)
// Conectar ao banco
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
// Criar service via factory
partnerService := factory.NewPartnerService(db)
// Criar um parceiro
dto := &factory.CreatePartnerDTO{
Email: "partner@example.com",
Name: "João Silva",
Role: factory.RolePartner,
}
partner, err := partnerService.CreatePartner(ctx, dto)Gerenciamento de parceiros/usuários do sistema.
Models: Partner, CreatePartnerDTO, UpdatePartnerDTO
Repository: IPartnerRepo
Service: IPartnerService
Factory: factory.NewPartnerService(db)
📖 Documentação: internal/models/prm/PARTNERS_README.md
Exemplo:
// Listar parceiros ativos
filters := &factory.PartnerFilterParams{
Status: ptr(factory.PartnerStatusActive),
Page: 1,
Limit: 20,
}
result, err := partnerService.ListPartners(ctx, filters)Sistema de onboarding guiado para novas empresas.
Models: OnboardingStatus, Pipeline, CommissionRule, SmtpSettings
Repository: 8 repositories (onboarding, smtp, templates, etc)
Service: IWizardService
Factory: factory.NewWizardService(db)
Funcionalidades:
- ✅ Status de onboarding
- ✅ Configuração de empresa (CNPJ + logo)
- ✅ Criação de pipeline com stages
- ✅ Configuração de comissão
- ✅ Configuração SMTP com teste
Exemplo:
// Inicializar onboarding
wizardService := factory.NewWizardService(db)
status, err := wizardService.InitializeOnboarding(ctx, companyID)
// Atualizar info da empresa
err = wizardService.UpdateCompanyCNPJAndLogo(ctx, companyID, "12.345.678/0001-90", logoBlob)Gerenciamento de clientes/customers.
Models: ClientDetailed
Repository: IClientRepo
Service: IClientService
Exemplo:
clientRepo := clients.NewClientRepo(ctx, dbService)
client, err := clientRepo.FindOne("id = ?", clientID)Autenticação e autorização OAuth2.
Models: OAuthClient, AuthCode
Repository: OAuth repositories
Service: OAuth services
| Tabela | Descrição | Module |
|---|---|---|
profiles |
Parceiros/Usuários | PRM |
companies |
Empresas | PRM |
pipelines |
Pipelines de vendas | PRM |
pipeline_stages |
Estágios do pipeline | PRM |
leads |
Leads/Oportunidades | PRM |
commissions |
Comissões de parceiros | PRM |
commission_rules |
Regras de comissão | PRM |
smtp_settings |
Configurações SMTP | PRM |
notification_templates |
Templates de notificação | PRM |
onboarding_status |
Status de onboarding | PRM |
user_invitations |
Convites de usuários | Auth |
As migrations são executadas automaticamente via embedded SQL files:
internal/bootstrap/embedded/
├── 001_init.sql # Schema inicial
├── 002_hardening.sql # Segurança e índices
├── 003_create_invites.sql # Sistema de convites
└── 004_wizard_and_missing_schema.sql # Wizard + complementos
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
dsn := "host=localhost user=postgres password=secret dbname=canalize_prm port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})sqlDB, _ := db.DB()
// Configurações de pool
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)O package factory expõe interfaces e construtores públicos:
// Partners
factory.NewPartnerService(db) IPartnerService
factory.NewPartnerRepo(db) IPartnerRepo
factory.Partner
factory.CreatePartnerDTO
factory.PartnerStatus
factory.PartnerRole
// Wizard
factory.NewWizardService(db) IWizardService
factory.OnboardingStatus
factory.Pipeline
factory.SmtpSettings
// Clients
factory.ClientDetailed// Gateway layer usa factory
import "github.com/canalize-prm/canalizedb/factory"
func InitServices(db *gorm.DB) {
partnerService := factory.NewPartnerService(db)
wizardService := factory.NewWizardService(db)
// ...
}# Todos os testes
go test ./...
# Com coverage
go test ./... -cover -coverprofile=coverage.out
# Ver coverage
go tool cover -html=coverage.outRequer PostgreSQL rodando:
# Subir banco para testes
docker run -d \
-e POSTGRES_PASSWORD=test \
-e POSTGRES_DB=canalize_test \
-p 5433:5432 \
postgres:14
# Executar testes
DB_TEST_PORT=5433 go test ./... -vJá criados nas migrations:
-- Profiles (Partners)
CREATE INDEX idx_profiles_email ON profiles(email);
CREATE INDEX idx_profiles_company_id ON profiles(company_id);
CREATE INDEX idx_profiles_status ON profiles(status);
-- Leads
CREATE INDEX idx_leads_company_id ON leads(company_id);
CREATE INDEX idx_leads_stage_id ON leads(stage_id);
CREATE INDEX idx_leads_assigned_to ON leads(assigned_to);
-- Pipelines
CREATE INDEX idx_pipelines_company_id ON pipelines(company_id);
CREATE INDEX idx_pipeline_stages_pipeline_id ON pipeline_stages(pipeline_id);- ✅ GORM usa prepared statements
- ✅ Eager loading com
Preload() - ✅ Paginação com
Limit()eOffset() - ✅ Índices em foreign keys
Isolamento por company_id:
// Repository level
query := db.Where("company_id = ?", companyID)PostgreSQL RLS policies (migrations):
-- Exemplo de policy
CREATE POLICY company_isolation ON leads
USING (company_id = current_setting('app.current_company_id')::uuid);- ✅ GORM sanitiza inputs automaticamente
- ✅ Prepared statements
- ❌ NUNCA use string concatenation
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})Output:
[2025-10-18 10:30:00] SELECT * FROM "profiles" WHERE email = 'test@example.com'import _ "net/http/pprof"
import "net/http"
go func() {
http.ListenAndServe("localhost:6060", nil)
}()Acesse: http://localhost:6060/debug/pprof/
- Repository: Apenas acesso a dados, sem validações
- Service: Validações e lógica de negócio
- Factory: Exports públicos e construtores
- Naming:
IXxxRepo,IXxxService,XxxDTO
-
Crie
internal/models/<module>/:<entity>_model.go<entity>_repo.go<entity>_service.go
-
Exponha via
factory/<module>.go:type IXxxService = module.IXxxService func NewXxxService(db *gorm.DB) IXxxService { repo := module.NewXxxRepo(db) return module.NewXxxService(repo) }
-
Documente em
README_<MODULE>.md
- ✅ Partners module completo
- ✅ Wizard module completo
- ✅ Clients module completo
- ✅ Factory exports
- ✅ Migrations automáticas
- ✅ Estrutura inicial
- ✅ Models básicos
- ✅ Repository pattern
MIT License - veja LICENSE para detalhes.
Rafael Mori
- Email: faelmori@gmail.com
- GitHub: @rafaelmorilima
Database layer built with ❤️ for Canalize PRM