v1.4: Segurança multi-tenant, file serving via API e UX humanizada

-  Validação cross-tenant no login e rotas protegidas
-  File serving via /api/files/{bucket}/{path} (eliminação DNS)
-  Mensagens de erro humanizadas inline (sem pop-ups)
-  Middleware tenant detection via headers customizados
-  Upload de logos retorna URLs via API
-  README atualizado com changelog v1.4 completo
This commit is contained in:
Erik Silva
2025-12-13 15:05:51 -03:00
parent 04c954c3d9
commit 2f1cf2bb2a
42 changed files with 2215 additions and 872 deletions

View File

@@ -188,17 +188,23 @@ func (r *TenantRepository) FindByID(id uuid.UUID) (*domain.Tenant, error) {
// FindBySubdomain finds a tenant by subdomain
func (r *TenantRepository) FindBySubdomain(subdomain string) (*domain.Tenant, error) {
query := `
SELECT id, name, domain, subdomain, created_at, updated_at
SELECT id, name, domain, subdomain, primary_color, secondary_color, logo_url, logo_horizontal_url, created_at, updated_at
FROM tenants
WHERE subdomain = $1
`
tenant := &domain.Tenant{}
var primaryColor, secondaryColor, logoURL, logoHorizontalURL sql.NullString
err := r.db.QueryRow(query, subdomain).Scan(
&tenant.ID,
&tenant.Name,
&tenant.Domain,
&tenant.Subdomain,
&primaryColor,
&secondaryColor,
&logoURL,
&logoHorizontalURL,
&tenant.CreatedAt,
&tenant.UpdatedAt,
)
@@ -207,7 +213,24 @@ func (r *TenantRepository) FindBySubdomain(subdomain string) (*domain.Tenant, er
return nil, nil
}
return tenant, err
if err != nil {
return nil, err
}
if primaryColor.Valid {
tenant.PrimaryColor = primaryColor.String
}
if secondaryColor.Valid {
tenant.SecondaryColor = secondaryColor.String
}
if logoURL.Valid {
tenant.LogoURL = logoURL.String
}
if logoHorizontalURL.Valid {
tenant.LogoHorizontalURL = logoHorizontalURL.String
}
return tenant, nil
}
// SubdomainExists checks if a subdomain is already taken