Follow-Up Sequences are intended to automate actions after a Campaign Call reaches a particular outcome.
A Sequence can be designed to respond to outcomes such as:
The intended Sequence workflow is:
The installed application includes database tables, models, API routes, user pages, scheduled jobs, enrollment statuses, action types, Smart Timing, and Analytics for Follow-Up Sequences. However, the current source contains several implementation defects that prevent the feature from operating reliably in production. This chapter explains both the intended user workflow and the verified current behavior.
The current Follow-Up Sequence module should be treated as:
The most significant current issues include:
Do not activate a Sequence for production Contacts until the core defects documented in this chapter have been corrected and tested.
From the Sidebar:
The main page address is:
The browser Sequence pages require:
when KYC is enabled.
The protected browser routes include:
Sequence creation and operational actions use API routes such as:
Enrollment operations use:
The browser pages use Basic KYC middleware.
The Sequence API routes are protected through Sanctum authentication and API throttling but do not contain the same KYC middleware.
An authenticated API user can therefore potentially access Sequence write operations even when the equivalent browser page is blocked by KYC.
This is a current access-control inconsistency.
A Customer’s browser Sequence page uses:
The Customer is intended to create and manage its own Sequences.
The browser Sequence controller maps an Agent to:
An Agent therefore sees Sequences owned by the parent Customer.
The Sequence policy allows an Agent to view the parent Customer’s Sequences.
It allows updates and deletion only when:
Because the Sequence belongs to the parent Customer, the Agent cannot update or delete it through the API.
The Sequence list and Details pages display:
without reliably hiding these actions from Agents.
An Agent can therefore see an action that the API later rejects.
The Agent can open:
The API creates the Sequence under the signed-in Agent’s own User ID.
After creation, the browser returns to /sequences, which lists the parent Customer’s Sequences rather than the Agent’s own Sequences.
The newly created Agent-owned Sequence can therefore disappear from the Agent’s normal browser list.
The Sequence policy permits an Administrator to view any Sequence through the API.
However, the normal browser Sequence list searches only:
The browser Details controller also manually checks direct ownership without an Administrator exception.
An Administrator therefore does not receive a normal system-wide Sequence-management interface.
The Sequence policy’s update and delete methods require direct ownership.
It does not include an Administrator override.
An Administrator can be allowed to view a Customer Sequence through the API but still be unable to update or delete it.
The main page is intended to display:
Each card is designed to show:
Trigger types are displayed as:
Deactivating a Sequence does not pause or stop its existing active Enrollments.
Priority can range from:
A higher number is intended to make the Sequence rank before lower-priority matching Sequences.
Example:
The intended engine loops through every matching Sequence.
Priority controls order, but the current design does not stop after selecting one Sequence.
A single Call outcome can therefore enroll a Contact into multiple matching Sequences.
The browser controller supports:
The current Sequence page does not render these Search and Filter controls.
Users cannot normally apply the supported backend filters through the visible page.
The browser controller returns:
The current Sequence index does not render pagination links.
When more than twelve Sequences exist, later pages are not normally accessible through the visible interface.
The Total Sequences Card shows an Active count based only on:
It does not count Active Sequences across every page.
The Sequence model defines its Step relationship using:
The actual Sequence Step table contains:
It does not contain:
The Sequence list eagerly loads Steps for every Sequence.
Once a Sequence exists, loading the list can therefore produce a database error similar to:
Select:
or open:
The page description states:
A new Sequence begins with approximately:
The visible Sequence fields are:
Name is required and limited to:
Example:
Use the Description to document:
The intended automatic engine assigns:
when a Call Status becomes:
The three outcomes are grouped under one Sequence Trigger.
The intended engine assigns:
when a Completed Call has:
Warm Lead Quality does not independently trigger Interested in the current Sequence engine.
The engine treats a Completed Call as Callback Requested when it finds a DTMF response with:
This rule is hard-coded.
It does not check whether the Campaign’s DTMF configuration actually defines 1 as Callback Requested.
A Campaign that uses:
can still trigger a Callback Requested Sequence.
A Completed Call with:
can trigger a Not Interested Sequence.
A Completed Call that does not match Callback Requested, Interested, or Not Interested falls back to:
A Manual Sequence is intended for enrollment through an explicit user or API action.
It is not selected automatically from a Call outcome.
Canceled Calls do not produce an automatic Sequence Trigger in the current engine.
For a Completed Call, the current order is:
Call completion can be processed before transcription and AI Sentiment Analysis finish.
When no Sentiment exists at the moment automatic Sequence enrollment runs, the Call can fall into:
rather than:
The current source does not show a later automatic re-evaluation after Sentiment becomes available.
The Sequence engine is designed to evaluate conditions based on:
Supported operators include:
The Sequence Builder does not display controls for configuring these conditions.
They can only be supplied through an API or custom administrative workflow.
The trigger evaluator reads:
The standard Call model uses:
A duration-based Trigger Condition can therefore receive a null value and fail to work correctly.
The backend supports:
to limit the total number of Enrollments permitted in a Sequence.
The visible Sequence Builder does not provide a Maximum Enrollments field.
The automatic engine calls a Sequence query scope named:
The current Sequence model does not implement that scope.
Automatic Sequence matching fails before capacity can be evaluated.
The Sequence Builder labels the feature:
When enabled, the engine attempts to identify an optimal time for a Contact before a Call Step.
Smart Timing is used only when:
It does not optimize:
The intended calculation is:
When Smart Timing cannot calculate an optimal Call time, the engine uses:
The application server currently operates in:
The Enrollment page formats dates in the browser’s locale but does not clearly display the scheduling Time Zone.
Confirm the actual UTC and local times before production use.
Every Sequence must contain at least:
A Step contains:
The supported Delay Units are:
A Delay Amount of:
represents an immediate Step.
A Step’s Delay is intended to occur before that Step executes.
Example:
The intended timeline is:
Select:
to append another Step.
New Steps default to:
Use the Up and Down controls to change Step order before saving.
The API assigns:
A Sequence must retain at least one Step.
The Delete control is disabled when only one Step remains.
The Call action is intended to dispatch another Campaign Call for the Enrollment’s Campaign Contact.
It uses:
The Builder displays an SMS Message field.
The Sequence engine currently only writes a log entry and returns:
It does not send an SMS through Twilio.
The Builder displays:
The Sequence engine currently only writes a log entry and returns:
It does not send an Email.
The Wait action returns:
and advances automatically.
It does not create a manual intervention task or hold the Enrollment until a user approves it.
The Builder displays a Webhook URL field.
The Sequence engine validates that a URL exists and then records a log entry.
It does not make an external HTTP request.
It returns:
even though no Webhook was actually transmitted.
The visible fields for:
do not have form-state bindings.
Typing into those fields does not update the Step’s:
object.
A Sequence created through the visible Builder normally submits:
for each Step.
Because the configuration is empty, the engine falls back to content such as:
These defaults are logged but not delivered.
The backend supports conditions that compare Enrollment Metadata using operators such as:
A Step can theoretically stop an Enrollment when:
A Sequence can theoretically stop based on:
The visible Sequence Builder does not expose:
These features require direct API or developer configuration.
The Call action returns:
The Step stop rule checks for:
to determine whether a Call connected.
The current Call Step therefore cannot satisfy the call_connected stop rule at the time the Step is executed.
The Builder submits to:
The API:
After creating the records, the API runs:
The Steps relationship orders by the nonexistent:
column.
This can produce a server error after the Sequence and its Steps were already saved.
When creation appears to fail:
The first request can have already inserted the Sequence before returning the error.
Repeated submissions can create duplicate Sequence records.
The Builder uses an Inertia form submission to a JSON API endpoint.
Inertia normally expects an Inertia response or redirect, while the API returns plain JSON.
The browser can report an invalid Inertia response even when the API operation otherwise succeeds.
From the Sequence card or Details page, select:
The address is:
The browser controller again orders Steps using:
The Edit page can fail before rendering.
When an update includes Steps, the API:
It does not update existing Step records individually.
The Sequence Step Execution table has a foreign key configured to delete execution records when a Step is deleted.
Editing a Sequence can therefore delete historical Step Execution records and destroy existing Step Analytics.
Existing Enrollments store:
rather than a direct Step ID.
Deleting and recreating Steps while Enrollments are active can cause those Enrollments to follow a changed workflow.
The Sequence update does not wrap deletion and recreation of Steps in a database transaction.
A failure during recreation can leave:
Do not edit a Sequence after Contacts have been enrolled.
Create a new Sequence version instead:
Activating changes:
An Active Sequence is intended to accept new automatic Enrollments.
Activation does not validate:
Activating a Sequence does not automatically enroll all existing Contacts.
An Enrollment still requires:
Deactivating changes:
Deactivation does not change existing Enrollment statuses.
Active Enrollments remain Active and can continue processing.
The confirmation dialog correctly warns:
The API refuses deletion when the Sequence has one or more Enrollments whose Status is:
The error advises the user to deactivate the Sequence.
Deactivating changes only is_active.
It does not change Active Enrollment statuses.
The Sequence remains undeletable after deactivation when Active Enrollments still exist.
The deletion check counts only Active Enrollments.
A Sequence with Paused Enrollments can pass the deletion check.
Sequences use soft deletion.
Deleting the Sequence records a deleted timestamp rather than hard-deleting the row.
Database cascade rules therefore do not automatically remove the related Enrollments and Steps in the same way as a hard delete.
The Sequence model supports soft deletion, but the policy and normal interface do not permit restoration.
Automatic enrollment is requested when a Campaign Call reaches one of these statuses:
The Call must have:
The Campaign Contact must also be linked to a master Contact.
When the Campaign Contact has no contact_id, the engine logs that no Contact exists and exits.
Campaign Contacts created through the current List-copy and CSV workflows do not reliably preserve a master Contact relationship.
Those Campaign Contacts may therefore be unable to enter automatic Follow-Up Sequences.
The engine is intended to choose Sequences that are:
The engine calls:
The Sequence model implements:
The required query scope does not exist under the name used by the engine.
The engine calls:
The Sequence model does not define that scope.
The engine calls:
The Sequence model does not define an enroll() method.
Because these core model methods are absent, automatic Sequence enrollment cannot complete successfully under the reviewed source.
The engine catches the exception and writes it to the application log, so the Call itself can complete while no Enrollment is created.
The manual endpoint is:
It requires:
Although the route is attached to a master Contact, it still requires a Campaign Contact.
A standalone Contact that has never participated in a Campaign cannot be enrolled through this endpoint without first obtaining a Campaign Contact record.
The current Contact and Sequence pages do not provide a normal visible manual Enrollment form.
Manual Enrollment is currently an API-oriented function.
The endpoint retrieves the submitted Campaign Contact but does not clearly verify that:
This is a current data-integrity and multitenant security concern.
The database prevents the same combination of:
from being enrolled more than once.
means the Enrollment is eligible for scheduled Step execution.
temporarily prevents the Enrollment from being selected by the due-Step processor.
Its next scheduled time remains stored.
means the workflow finished without being explicitly marked as Converted.
represents a successful business outcome.
means the Enrollment was manually or conditionally ended before ordinary completion.
A Stop Reason can be stored.
The Sequence engine includes a method that can mark an Enrollment Converted and store an optional Conversion Reason.
The reviewed source contains no other call to that conversion method.
The ordinary workflow does not automatically mark Enrollments as Converted.
Converted Analytics can therefore remain zero unless another API, database process, or future integration sets the Status.
The API route is:
It changes:
Pause does not clear:
The scheduled time remains recorded.
The API route is:
When the stored next_step_at is already in the past, Resume changes it to:
The Step can become due immediately.
Resume does not reset:
It continues from the stored position.
The route is:
The request requires:
Stopping changes:
The current Sequence Details page does not display normal buttons for:
These actions exist only through API routes in the reviewed interface.
Laravel schedules:
to run:
The scheduled job uses withoutOverlapping.
Laravel’s scheduler must be invoked by the server cron system.
Without an active scheduler:
The processor selects Enrollments where:
The job processes up to:
per batch.
When one hundred Enrollments are found, the job dispatches another processor approximately ten seconds later.
The production runtime currently uses:
Jobs execute in the same process rather than through independent background workers.
With the synchronous driver:
Before executing, the job confirms:
The individual job declares:
The Sequence engine catches Step action exceptions and returns:
instead of rethrowing them.
Because the queued job does not receive an exception, its configured retry mechanism is not normally triggered for these action failures.
A failed Step can leave the Enrollment:
The scheduler can select it again during the next minute, causing repeated failures.
A Call Step dispatches:
using the Enrollment’s Campaign Contact.
The Enrollment must have:
A Manual Sequence Enrollment still depends on an existing Campaign Contact and Campaign.
The Sequence engine marks the Step successful when the Call job is queued.
It does not wait for the resulting telephone Call to:
The Step Execution table contains a call_id field.
The Call action does not populate that field in the reviewed code.
The Sequence Execution cannot be directly traced to the resulting Call through this relationship.
Under the current design:
It does not mean:
Every Step already has a Delay.
A Wait Step then completes without another external action.
Example:
The intended total delay before the Call can become approximately:
A Wait Step is not a manual approval pause.
The database initializes:
The method for finding the next Step searches for:
Unless enrollment creation explicitly overrides current_step to zero, the first Step can be skipped.
The missing Sequence enroll() method prevents confirmation of a proper override.
After a Step executes, the engine:
moveToNextStep() already changes current_step to the next Step.
scheduleNextStep() then searches for another Step after that value.
This can skip every second Step.
Intended:
Possible current behavior:
Step 2 never executes.
When a Step fails its condition, scheduleNextStep() calls:
That method can set the condition-failing Step as the current due Step.
The execution job does not recheck the Step condition.
A Step that was supposed to be skipped can later execute anyway.
The engine creates one Step Execution with:
After success, it calls:
which creates a second Step Execution record with:
The original Executing record is also changed to Completed.
One successful Step can therefore produce two completed execution records.
Step statistics can report:
for one actual Step run.
Execution counts and Success Rates should not be treated as accurate until this duplicate-record path is corrected.
The address is:
The intended page contains:
Each Step is intended to show:
Each Enrollment is intended to display:
The page formats next_step_at using a date-only display.
It does not show the exact scheduled hour or Time Zone.
The Enrollment Cards do not provide:
The Sequence Analytics tab is intended to show:
The Details controller orders Steps by:
which does not exist.
The controller attempts to eager-load:
The Sequence Enrollment model does not define a currentStep() relationship.
It provides a method named:
which cannot be eager-loaded as a relationship.
The controller queries:
The actual table is:
The controller builds Step performance using:
The actual field is:
The controller sends Analytics in a nested structure containing:
The frontend expects top-level properties such as:
The expected frontend properties are not provided under those names.
The Sequence Details page can fail through:
The Steps, Enrollments, and Analytics tabs are not dependable in the current build.
Each Sequence stores:
Enrollment completion calls:
The Sequence model does not define that method.
The stored Sequence counters are not reliably recalculated.
The Sequence list displays the stored counters rather than the actual relationship counts.
Cards can continue showing:
even when Enrollment rows exist.
The top-level Total Enrolled Card uses a direct database count of Sequence Enrollments.
It can therefore disagree with the individual Sequence cards.
The Sequence list calculates:
An Enrollment cannot normally be both:
Converted and Completed are separate Statuses.
Example:
The denominator should likely include both completed and converted terminal outcomes.
The API Sequence Analytics service calls:
The Sequence model does not define that method.
The service also calls:
The Sequence model does not define that method.
The API endpoint:
can fail before returning Analytics.
SMS, Email, and Webhook placeholders return successful-looking result strings.
They can be counted as successful even though nothing was delivered externally.
A Call Step can be counted as successful when its Call job is queued, regardless of the final telephone outcome.
Current Step Success Rate is closer to:
than:
A Sequence Call uses the Campaign Call job.
The Call can therefore create:
depending on the Campaign configuration.
The Sequence Builder does not provide:
max_enrollments is intended to limit Enrollment quantity.
It does not represent a financial limit.
After the module is repaired, begin with:
Do not begin with:
Create separate controlled tests for:
This is consistent with the invalid step_order column.
The empty list may load because there are no Step relationships to query.
After the first Sequence is stored, eager-loading Steps can cause the database error.
The Sequence and Steps can be inserted before the invalid Step relationship is loaded.
Check the database before submitting again.
The page counts Active Sequences only within the currently loaded twelve records.
The backend paginates, but the page does not display pagination controls.
Agents can view the parent Customer’s Sequence, but API update policy requires direct ownership.
Possible causes include:
Sentiment may not have existed when the Call completion handler requested Sequence enrollment.
The Sequence engine hard-codes DTMF digit 1 as Callback Requested.
CSV Campaign Contacts are not reliably linked to master Contacts.
The Sequence engine requires that relationship.
The Enrollment can begin with current_step = 1, while the engine searches for a Step greater than the current Step.
The engine moves to the next Step and then schedules another next Step, causing double advancement.
The condition-skipping path can set the skipped Step as current and due.
The execution job does not re-evaluate the condition.
The SMS action is a placeholder and does not send a message.
The Email action is a placeholder and does not send Email.
This is separate from the platform’s current log mail driver.
The Webhook action logs information but does not make an HTTP request.
The Step is marked successful when the Call job is queued.
Review Call History for the telephone result.
The actions exist only through API routes.
The current Details page does not expose them.
The action engine catches errors and returns false without engaging the job retry system.
The overdue Enrollment can be selected again every minute.
Stop or pause it through an approved API process.
The method that marks an Enrollment Converted is not called by another reviewed workflow.
The deletion check blocks a Sequence with Active Enrollments.
Deactivating the Sequence does not change their status.
Likely causes include:
The controller and frontend use different Analytics property names.
One successful Step can create two execution records.
The current overview divides Converted by Completed even though those are separate terminal statuses.
The overview counts database Enrollments directly.
The individual cards rely on stored Sequence counters that are not being updated correctly.
Replace:
with:
throughout the Sequence model and browser controllers.
Implement or correct:
Alternatively, update the engine to use correctly named existing methods where appropriate.
Initialize a new Enrollment so the first Step is scheduled exactly once.
A consistent design would normally start before Step 1 rather than marking Step 1 current before it has executed.
Use one operation to:
Do not call two separate methods that both advance the Step position.
Create one Execution record per Step attempt.
Update that same record from:
Connect:
Connect visible SMS, Email, and Webhook fields to:
Correct:
Do not delete and recreate all Steps for a Sequence with history.
Use Step versioning or block structural editing once Enrollments exist.
Hide or disable actions that the signed-in role cannot perform.
Align browser ownership, API ownership, Administrator access, and Agent access.
Verify that:
all belong to the same authorized workspace.
Confirm:
Confirm:
Confirm:
Confirm:
Confirm:
Confirm:
Confirm:
Monitor:
Confirm:
The reviewed Follow-Up Sequence implementation currently includes these important limitations:
At the end of this chapter, the user should understand that a Follow-Up Sequence is intended to connect a Campaign Call outcome to a timed set of automated Steps.
The user should understand the six Trigger Types:
The user should know that an Active Sequence accepts new matching Enrollments while deactivation prevents new automatic Enrollments without stopping existing ones.
The user should understand the five Enrollment Statuses:
and the five available Step Action Types:
The user should recognize that only the Call and Wait handlers contain meaningful processing logic in the reviewed build. SMS, Email, and Webhook actions currently record placeholder success results without transmitting anything.
The user should understand that Sequence Steps are intended to run through Laravel’s scheduler every minute and that the current synchronous Queue driver processes them sequentially.
The user should also recognize that the current Sequence engine is not operationally dependable because it references missing model methods, uses an invalid Step-ordering column, can skip Steps, can duplicate execution records, and cannot reliably display Sequence Details or Analytics.
Most importantly, the current safe rule is: