ORVIAN’s Communications module integrates two external services: Evolution API (WhatsApp) for automated attendance alerts sent to student tutors, and Chatwoot for a web-based messaging center accessible by school directors. Both services are optional and configured entirely through environment variables — neither requires code changes to enable or disable.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Elian-D/ORVIAN/llms.txt
Use this file to discover all available pages before exploring further.
WhatsApp via Evolution API
WhatsApp messaging in ORVIAN is handled byWhatsAppService (app/Services/Communications/WhatsAppService.php), a singleton HTTP client registered in AppServiceProvider. Key architectural decisions:
- Sender-only — ORVIAN dispatches WhatsApp messages but does not process or listen for incoming messages. There are no webhooks or inbound message handlers.
- Asynchronous delivery — all message sending happens through
SendAttendanceAlertJob, a queued job with 3 retries and a 60-second backoff. This ensures a failed Evolution API call never blocks the web request or delays attendance recording. - Anti-spam cache —
AttendanceAlertEvaluatorprotects against alert flooding with a weekly cache key per student per alert type (e.g.,alert_absence_{student_id}_{weekOfYear}andalert_tardiness_{student_id}_{weekOfYear}, TTL 7 days). A tutor receives at most one absence alert and one tardiness alert per calendar week, regardless of how many times the evaluator runs. - Phone normalization — Evolution API expects the phone number without the leading
+.WhatsAppService::sendTextMessage()strips it automatically:$normalizedPhone = ltrim($phone, '+').
Setting Up Evolution API
Deploy Evolution API on your VPS
Follow the Evolution API documentation to install and start the service on your server. Evolution API can run as a Docker container or a Node.js process.
Create and connect a WhatsApp instance
In the Evolution API manager, create a new instance and scan the QR code with the WhatsApp account that will send messages on behalf of the school. Wait for the state to show
open (connected).Note your credentials
Collect three values from your Evolution API setup:
- Instance name — the exact name you gave the instance (e.g.,
orvian-demo) - API URL — the base URL of your Evolution API server (e.g.,
https://evolution.orvian.com.do) - API key — the global API key configured in Evolution API
Test the integration
Run the demo command to force-fire test alerts for a specific school (pass the school ID as an argument):Replace
1 with your actual school ID. The command clears the anti-spam cache for that school’s students and immediately re-evaluates them, so alerts are dispatched even if they were already sent this week.Check Laravel logs (storage/logs/laravel.log) for WhatsAppService: Mensaje enviado entries confirming successful delivery, or WhatsAppService: Respuesta no exitosa with the Evolution API status code if something is misconfigured.WhatsApp Message Format
ORVIAN uses two message templates defined inWhatsAppTemplates (app/Services/Communications/WhatsAppTemplates.php). Both use WhatsApp’s native text formatting — *bold* and _italic_.
Absence alert (absenceAlert):
tardinessAlert):
su representado / su representada) is derived from the student’s gender field (M / F) in the database. The tutor name comes from students.tutor_name and the phone from students.tutor_phone.
Alert Scheduling
Theorvian:evaluate-attendance-alerts Artisan command scans all active students, evaluates their monthly absence and tardiness counts against the configured thresholds (default: 3 for each), and dispatches SendAttendanceAlertJob for qualifying students.
-
Scheduled at 16:00 daily in
routes/console.php, withwithoutOverlapping()to prevent concurrent runs if a previous execution is still processing a large school. -
Thresholds are configurable via
.env: -
Manual run for a specific school:
-
Manual run for all schools:
tutor_phone).
Setting Up Chatwoot
Deploy Chatwoot or use the hosted instance
You can self-host Chatwoot on your VPS by following the Chatwoot deployment guide, or use the ORVIAN-managed instance at
chat.orvian.com.do if your contract includes it.Create a Superadmin account and note the API token
Log into Chatwoot as a Superadmin. Go to Profile Settings → Access Token and copy the API access token. This is the token ORVIAN uses for all server-to-server API calls (agent creation, conversation queries).
Note your Account ID
The account ID is visible in the Chatwoot URL when logged in:
https://chat.orvian.com.do/app/accounts/1/.... It is typically 1 for single-tenant deployments.Generate an HMAC token for SSO
In Chatwoot, go to Settings → Integrations → Identity Verification. Generate or copy the HMAC token for the inbox you want to use for SSO. This token must match
CHATWOOT_HMAC_TOKEN in Laravel exactly — it is the shared secret used to sign user identity.How Chatwoot SSO Works
ORVIAN uses full-redirect SSO with Chatwoot’s Identity Verification feature — no iframe is embedded in the dashboard. When a Director clicks the Messages tile:-
Laravel’s controller calls
ChatwootService::generateIdentifierHash($user->email), which computes:This hash is computed server-side only and never exposed to the browser or JavaScript. -
The controller builds a redirect URL:
-
The browser is redirected to that URL. Chatwoot verifies the
identifier_hashagainst its own copy of the HMAC token. If the signature matches, Chatwoot logs the user in automatically. - The Director lands directly in the Chatwoot inbox — no separate login is required.
CHATWOOT_HMAC_TOKEN must never appear in client-side code, JavaScript bundles, or API responses. It is a server-side secret.
Agent Sync
When a school completes onboarding (either viaCompleteOnboardingAction or CompleteTenantOnboardingAction), the Director is automatically registered as a Chatwoot agent:
DB::afterCommit ensures the agent sync only runs after the database transaction commits successfully — preventing orphaned Chatwoot agents if the onboarding transaction rolls back.
ChatwootService::syncUserAsAgent() logic:
- Calls
findAgentByEmail()to check whether the Director already exists as an agent (prevents duplicates on re-runs). - If not found, calls
createAgent()with the Director’sname,email, androle: 'agent'. - On success, stores the Chatwoot agent ID in
users.preferences['chatwoot_agent_id']for future reference. - Any exception thrown during the entire sync flow is caught by a
try/catchblock and written to the Laravel log as aChatwootService: Error en sincronizaciónerror entry — preventing a failed Chatwoot sync from rolling back the onboarding transaction.
The
communications module tile must have visible: true in config/modules.php for the Messages link to appear on the school dashboard. This is true by default as of v0.5.0. In earlier versions (v0.4.0–v0.4.1), the tile was set to visible: false and the module was listed as coming soon.Troubleshooting
WhatsApp messages not sending
WhatsApp messages not sending
- Verify that
EVOLUTION_INSTANCE_NAMEin your.envexactly matches the instance name in your Evolution API manager — it is case-sensitive. - Open the Evolution API manager and confirm the instance status is
open(connected). Instances can expire or disconnect if the WhatsApp session is invalidated (phone logged out, number banned, inactivity). - Check the Laravel log for
WhatsAppService: Respuesta no exitosa— the loggedstatusandbodyfields will show the Evolution API error code. - Ensure the queue worker is running (
php artisan queue:work) —SendAttendanceAlertJobis dispatched asynchronously and will not run without a worker.
Chatwoot SSO login fails
Chatwoot SSO login fails
The most common cause is a mismatch between the
CHATWOOT_HMAC_TOKEN in Laravel and the token configured in Chatwoot’s Identity Verification settings.- Go to Chatwoot → Settings → Integrations → Identity Verification and copy the token shown there.
- Paste it into
CHATWOOT_HMAC_TOKENin your Laravel.env. - Run
php artisan config:clearto reload the configuration. - Try the SSO redirect again. If it still fails, verify that the
emailbeing passed matches exactly what Chatwoot expects (no trailing spaces, correct domain).
No agents in Chatwoot after onboarding
No agents in Chatwoot after onboarding
- Check
storage/logs/laravel.logforChatwootService: Error en sincronizaciónentries — these will contain the exception message. - Check the Chatwoot admin panel directly for the agent. The
syncUserAsAgent()call only logs a success message (ChatwootService: Agente creado exitosamente) or an exception — it does not log the raw HTTP response body. A422 Unprocessable Entityfrom the Chatwoot API typically means the email is already taken under a different account. - If the agent was partially created, use the Chatwoot admin panel to delete the duplicate and re-trigger sync by re-running the onboarding action, or call
ChatwootService::syncUserAsAgent($user)manually in a Tinker session. - Confirm
CHATWOOT_API_ACCESS_TOKENbelongs to a Superadmin account — agent creation requires Superadmin privileges.
Student's tutor not receiving alerts
Student's tutor not receiving alerts
- Verify that the student’s
tutor_phonefield is populated and in E.164 format:+1XXXXXXXXXXfor Dominican numbers (e.g.,+18091234567). Formats like809-123-4567or8091234567(without country code) will fail. - Check whether the anti-spam cache is suppressing the alert. The cache key
alert_absence_{student_id}_{weekOfYear}prevents more than one absence alert per week per student. To force re-send during testing, runphp artisan cache:clear(note: this clears all cache). - Look for
AttendanceAlertEvaluatorlog entries — students withouttutor_phoneare silently skipped and reported in the evaluator’s skipped report, not as errors. - Confirm the WhatsApp instance is active and the tutor’s number is not blocked in WhatsApp.