Skip to main content

Business Communication Configuration Guide

Overview​

The Business Communication Configuration Matrix controls how each business sends communications across all supported channels. Every combination of (business Γ— communication type Γ— channel) has its own configuration row that governs:

  • Whether that channel is enabled for that type
  • Whether messages are sent automatically or require manual dispatch
  • Template overrides
  • Time-window restrictions (e.g. business hours only)
  • Rate limits and minimum send intervals
  • Custom JSON conditions (e.g. minimum transaction amount)
  • Admin notes

Key Concepts​

Configuration Matrix​

The matrix is a 3-dimensional grid:

DimensionValues
BusinessUUID
Communication Typeinvoice, sale, payment_confirmation, payment_link, collection_notice, low_stock_alert, general_notification, invitation, user_invitation, daily_report, emergency_alert, order_confirmation, refund_confirmation, reminder, materialConsumption, creditNote, debitNote, felCancellation, cashRegisterSession, quote
Channelemail, sms, whatsapp, messenger, pdf

Configuration Fields​

FieldTypeDescription
isEnabledbooleanWhether this channel is active for this type
isAutomaticbooleanAuto-send on trigger vs. manual dispatch
templateIdUUID?Template override (uses default when null)
sendDelayMinutesint?Minutes to wait before sending (0–1440)
sendTimeWindowStartstring?Window start in HH:mm or HH:mm:ss format (validated by regex)
sendTimeWindowEndstring?Window end in HH:mm or HH:mm:ss format (validated by regex)
timezonestring?IANA timezone string β€” stored for reference; server-side timezone enforcement is not yet implemented
maxSendsPerRecipientPerDayint?Daily rate limit per recipient (1–100) β€” not yet enforced (requires communication history table)
minIntervalMinutesint?Minimum minutes between sends to same recipient β€” not yet enforced
conditionsjsonb?Custom rule object (see Conditions section)
notesstring?Admin notes

Authentication & User Identity​

All mutation endpoints (POST, PUT, DELETE) derive createdBy, updatedBy, and deletedBy from the authenticated Firebase user via the @UserId() decorator. These fields are not accepted as client input β€” they are set server-side from the JWT token.

canSend() Fail-Open Strategy​

The canSend() method is designed fail-open: if no configuration is found, or if an error occurs during evaluation, it returns allowed: true. This ensures that missing configuration never silently blocks a communication.

Rate Limiting & Interval Checks β€” Not Yet Active​

The maxSendsPerRecipientPerDay and minIntervalMinutes fields are stored and returned in the API, but the canSend() enforcement for these two rules requires querying a communication-history table that is not yet implemented. The fields currently have no runtime effect. Tracked as a TODO in the service.

Time Window Enforcement​

sendTimeWindowStart / sendTimeWindowEnd are enforced in canSend() using server UTC time. The timezone field is stored but not yet applied to the comparison. Overnight windows are supported (e.g. 22:00–06:00).

Custom Conditions​

conditions is a free-form JSON object. Currently supported keys:

KeyTypeBehavior
min_amountnumberBlock send if context.amount < min_amount
max_amountnumberBlock send if context.amount > max_amount

Unknown keys are ignored. Fail-open on parse errors.


Default Initialization​

Calling POST /business-communication-config/business/:businessId/initialize upserts defaults for all types Γ— channels:

ChannelDefault isEnabledDefault isAutomatic
emailtruetrue for invoice, payment_confirmation, invitation, user_invitation; false for all others
smsfalsefalse
whatsappfalsefalse
messengerfalsefalse
pdffalsefalse

Default time window: 08:00–20:00 UTC. Default rate limit: 5/day, 60 min interval.

The endpoint is idempotent β€” safe to call multiple times.


API Endpoints​

Base path: /business-communication-config

MethodPathDescription
GET/business/:businessIdList all configs for a business
GET/business/:businessId/type/:typeGet enabled channels for a type β†’ { channels: string[] }
GET/business/:businessId/type/:type/channel/:channelGet specific config (404 if not found)
GET/business/:businessId/type/:type/channel/:channel/can-sendValidate send permission
POST/Create a single config
PUT/:idPartial update a config (immutable: businessId, communicationType, channel)
DELETE/:idDelete a config
POST/business/:businessId/initializeInitialize defaults (idempotent)
POST/bulk-updateUpsert multiple configs at once

All endpoints require Authorization: Bearer <firebase-id-token>. User identity for audit trail is derived from the token automatically.

can-send query params​

ParamRequiredDescription
recipientIdNoEnables rate-limit and interval checks (currently stubbed)
amountNoUsed by min_amount / max_amount conditions

Update constraints​

The PUT /:id endpoint does not allow changing businessId, communicationType, or channel β€” these are immutable identity fields. To change them, delete and re-create the configuration.


Example Requests​

Create a config​

POST /business-communication-config
Authorization: Bearer <firebase-id-token>
{
"businessId": "550e8400-e29b-41d4-a716-446655440000",
"communicationType": "invoice",
"channel": "email",
"isEnabled": true,
"isAutomatic": true,
"sendTimeWindowStart": "08:00",
"sendTimeWindowEnd": "20:00",
"timezone": "America/Guatemala",
"maxSendsPerRecipientPerDay": 3,
"minIntervalMinutes": 60,
"notes": "Auto-send invoices via email during business hours"
}

Bulk update (typical UI save)​

POST /business-communication-config/bulk-update
Authorization: Bearer <firebase-id-token>
{
"businessId": "550e8400-e29b-41d4-a716-446655440000",
"configs": [
{ "communicationType": "invoice", "channel": "email", "isEnabled": true, "isAutomatic": true },
{ "communicationType": "invoice", "channel": "whatsapp", "isEnabled": true, "isAutomatic": false },
{ "communicationType": "payment_confirmation", "channel": "sms", "isEnabled": false, "isAutomatic": false }
]
}

Check can-send with amount condition​

GET /business-communication-config/business/{id}/type/invoice/channel/email/can-send?amount=150

Response:

{ "allowed": true, "reason": "All configuration checks passed" }

Audit Trail​

Every createConfig, updateConfig, deleteConfig, and bulkUpdate operation is recorded in business_communication_config_audit with:

  • configId, businessId, communicationType, channel
  • action: created | updated | deleted
  • previousValue / newValue: full config snapshots
  • changedBy: user UUID (derived from authenticated Firebase token)
  • reason: free-text change reason (supported in updateConfig via the reason DTO field)

Architecture Notes​

The module follows strict Hexagonal Architecture:

domain/   β†’ IBusinessCommunicationConfigRepository (port), BusinessCommunicationConfig types, CanSendResult/SendTimeWindow value types
application/ β†’ BusinessCommunicationConfigService (use cases)
infrastructure/ β†’ BusinessCommunicationConfigRepository (Kysely adapter)
interfaces/ β†’ BusinessCommunicationConfigController (HTTP), request DTOs, response DTOs

The service is exported from the module so other modules (e.g. the communications dispatcher) can inject it directly to call canSend(), shouldAutoSend(), getSendDelay(), and getTemplateOverride().


Known Limitations & TODOs​

  1. Rate limiting β€” maxSendsPerRecipientPerDay stored but not enforced. Requires a communication history table query.
  2. Min interval β€” same as above.
  3. Timezone-aware time windows β€” timezone field stored but server compares against local server time. Needs luxon or date-fns-tz integration.