Files
mercado.clube67.com/backend/middleware/tenant.js
T

89 lines
2.7 KiB
JavaScript

'use strict'
const { queryOne } = require('../database/postgres')
// Cache simples em memória — evita query por request (TTL 60s)
const cache = new Map()
const CACHE_TTL = 60_000
async function resolveTenant(identifier) {
const now = Date.now()
if (cache.has(identifier)) {
const hit = cache.get(identifier)
if (now - hit.ts < CACHE_TTL) return hit.tenant
cache.delete(identifier)
}
const tenant = await queryOne(
`SELECT t.*, tc.primary_color, tc.secondary_color, tc.logo_url,
tc.favicon_url, tc.contact_email, tc.contact_phone, tc.app_url, tc.asaas_key
FROM tenants t
LEFT JOIN tenant_config tc ON tc.tenant_id = t.id
WHERE (t.domain = $1 OR t.slug = $1) AND t.active = true
LIMIT 1`,
[identifier]
).catch(() => null)
if (tenant) cache.set(identifier, { tenant, ts: now })
return tenant
}
// Middleware principal — anexa req.tenant
async function tenantMiddleware(req, res, next) {
try {
// 1. Tenta pelo subdomínio (hostname sem porta)
const hostname = (req.hostname || '').split(':')[0]
const subdomain = hostname.split('.')[0]
let tenant = null
// Tenta pelo hostname completo primeiro (para domínios customizados)
if (hostname && hostname !== 'localhost') {
tenant = await resolveTenant(hostname)
}
// Tenta pelo subdomínio
if (!tenant && subdomain && subdomain !== 'localhost' && subdomain !== 'www') {
tenant = await resolveTenant(subdomain)
}
// Tenta pelo header X-Tenant-Slug (útil para dev e APIs internas)
if (!tenant && req.headers['x-tenant-slug']) {
tenant = await resolveTenant(req.headers['x-tenant-slug'])
}
// Fallback: tenant padrão (id=1, slug=alemao) — garante funcionamento local
if (!tenant) {
tenant = await resolveTenant('alemao')
}
if (!tenant) {
return res.status(503).json({ error: 'Tenant não encontrado ou inativo.' })
}
req.tenant = tenant
next()
} catch (err) {
console.error('[tenant middleware]', err.message)
return res.status(503).json({ error: 'Serviço temporariamente indisponível' })
}
}
// Middleware para rotas de admin — verifica que admin pertence ao tenant
function tenantAdminMiddleware(req, res, next) {
if (!req.admin || !req.tenant) return next()
// Se admin tem tenant_id definido, deve bater com o tenant da request
if (req.admin.tenant_id && req.admin.tenant_id !== req.tenant.id) {
return res.status(403).json({ error: 'Acesso negado a este tenant.' })
}
next()
}
// Limpar cache (útil após update de tenant_config)
function invalidateTenantCache(identifier) {
if (identifier) cache.delete(identifier)
else cache.clear()
}
module.exports = { tenantMiddleware, tenantAdminMiddleware, invalidateTenantCache }