Interview Lifecycle - Technical Manual

Version: 1.0
Last Updated: 2026-07-16

This guide is intended for Developers, Architects, DevOps, and System Integrators.


Purpose

The InterviewExecution entity serves as the aggregate root for all survey interview operations. It represents a single survey session with a respondent and manages the complete lifecycle from creation to final submission.

Unlike traditional form-filling approaches that treat each submission as independent, MQUAD's interview model provides:

  • State Persistence: Interview progress survives app restarts and connectivity loss
  • Lifecycle Tracking: Explicit status transitions enable workflow automation
  • Multi-Device Support: Interviews can be resumed across devices
  • Revision Management: Rejected interviews maintain context for corrections

Responsibilities

InterviewExecution

The InterviewExecution aggregate owns:

  • Overall interview status and state machine
  • Session token for authentication
  • Progress tracking (current_page, answered_count)
  • Response linkage (current_response_id)
  • Interview metadata and timestamps

FormSession

The FormSession entity manages:

  • Runtime form state during filling
  • Draft responses while offline
  • Position and navigation state
  • Session-specific validation cache

SurveyResponse

The SurveyResponse entity owns:

  • Final response data after completion
  • Status transitions (draft → submitted → approved/rejected)
  • Answer records (ResponseAnswer)
  • Edit history (ResponseEdit)
  • Review workflow state

Sync Service

The sync-service handles:

  • Offline queue management
  • Conflict detection and resolution
  • Device synchronization
  • Interview state persistence across devices

Form Service

The form-service manages:

  • Interview lifecycle transitions
  • State validation and business rules
  • Event publishing for state changes
  • Response submission coordination

Data Service

The data-service manages:

  • Response storage and retrieval
  • Answer validation against schemas
  • Webhook event generation
  • Audit trail persistence

State Machine

Diagram; its source is available below
Diagram source
stateDiagram-v2
    [*] --> Created: Initial state
    Created --> InProgress: First question answered
    InProgress --> Paused: Explicit pause or timeout
    InProgress --> Interrupted: System error
    InProgress --> Completed: All questions answered
    InProgress --> Terminated: Premature end
    Paused --> InProgress: Resume session
    Interrupted --> InProgress: Recovery action
    Completed --> NeedsRevision: Supervisor rejection
    NeedsRevision --> InProgress: Revision started
    NeedsRevision --> Completed: Revision complete

State Transitions

Created → In Progress

PropertyValue
TriggerFirst answer saved or explicit start
ValidationSurvey must be published
Database Updatesstatus = 'in_progress', started_at = now()
Events PublishedNone (implicit in first answer)
Services InvolvedForm Service
Failure BehaviourInterview remains in "created" state
IdempotencyStarting an already-in-progress interview is idempotent

In Progress → Paused

PropertyValue
TriggerExplicit pause or session timeout
ValidationInterview must exist and be active
Database Updatesstatus = 'paused', paused_at = now()
Events PublishedNone
Services InvolvedForm Service
Failure BehaviourInterview remains in "in_progress"

In Progress → Interrupted

PropertyValue
TriggerSystem error or unexpected closure
ValidationNone required
Database Updatesstatus = 'interrupted'
Events PublishedNone
Services InvolvedForm Service
Failure BehaviourRequires manual recovery

In Progress → Completed

PropertyValue
TriggerAll questions answered and submit called
ValidationAll required questions must have answers
Database Updatesstatus = 'completed', completed_at = now(), response_rid, response_uid populated
Events Publishedresponse.submitted
Services InvolvedForm Service, Data Service
Failure BehaviourInterview remains in "in_progress"

In Progress → Terminated

PropertyValue
TriggerExplicit termination or system failure
ValidationTermination reason required
Database Updatesstatus = 'terminated', terminated_at = now(), termination_reason set
Events PublishedNone
Services InvolvedForm Service
Failure BehaviourInterview remains in "in_progress"

Completed → Needs Revision

PropertyValue
TriggerSupervisor rejection
ValidationResponse must exist and be rejected
Database Updatesstatus = 'needs_revision', current_response_id set
Events Publishedresponse.rejected (triggers interview transition)
Services InvolvedData Service (via event), Form Service
Failure BehaviourInterview remains in "completed"

Needs Revision → In Progress

PropertyValue
TriggerEnumerator begins revision
ValidationInterview must be in "needs_revision" state
Database Updatesstatus = 'in_progress'
Events PublishedNone
Services InvolvedForm Service

Needs Revision → Completed

PropertyValue
TriggerRevision finished and resubmitted
ValidationAll corrections must be applied
Database Updatesstatus = 'completed', current_response_id cleared
Events PublishedResponse update events
Services InvolvedForm Service, Data Service

Needs Revision Workflow

Diagram; its source is available below
Diagram source
sequenceDiagram
    participant Sup as Supervisor
    participant DS as Data Service
    participant Event as Event Bus
    participant FS as Form Service
    participant Enum as Enumerator

    Sup->>DS: PATCH /responses/{id}/reject
    Note over DS: Mark response rejected
    Note over DS: Publish response.rejected event

    Event-->>FS: Receive response.rejected
    Note over FS: Lookup InterviewExecution<br/>by current_response_id

    FS->>FS: Update status to needs_revision
    Note over FS: Set current_response_id

    Enum->>FS: GET /interviews/{id}
    Note over FS: Return interview with needs_revision status

    Enum->>FS: PATCH /interviews/{id}/transition
    Note over FS: Set status = in_progress

    Enum->>FS: PATCH /responses/{id}/edit
    Note over FS: Apply corrections

    Enum->>FS: POST /interviews/{id}/complete
    Note over FS: Clear current_response_id<br/>Set completed_at

Aggregate Design

InterviewExecution as Aggregate Root

InterviewExecution is the aggregate root because:

  • Single source of truth for interview lifecycle
  • Clear ownership boundary for state transitions
  • Facilitates optimistic locking via version columns
  • Enables CQRS pattern for query separation

SurveyResponse Separation

SurveyResponse is separate because:

  • Responses may exist without interviews (direct submission)
  • Audit trail requires immutable response history
  • Multiple interview revisions map to one response chain
  • Review workflow operates at response level

FormSession Runtime State

FormSession owns runtime state because:

  • Sessions are ephemeral compared to interviews
  • Multiple sessions may reference one interview
  • Session data is cache-like and can be rebuilt
  • Separation enables efficient cleanup

Event Driven Architecture

Events

EventSourceTrigger
response.submitteddata-serviceResponse created
response.approveddata-serviceSupervisor approves
response.rejecteddata-serviceSupervisor rejects
response.editeddata-serviceResponse modified
interview.createdform-serviceInterview initialized
interview.startedform-serviceStatus → in_progress
interview.completedform-serviceStatus → completed
interview.pausedform-serviceStatus → paused
interview.terminatedform-serviceStatus → terminated
interview.needs_revisionform-serviceResponse rejection handler

Session Management

Heartbeat

Heartbeats are sent every 30 seconds while interviews are in progress:

  • Updates last_heartbeat_at timestamp
  • Enables crash detection and recovery
  • Prevents stale session conflicts
  • Triggers timeout if missed for > 2 minutes

Pause

Pausing preserves interview state:

  • No heartbeats sent while paused
  • Interview unlocked but locked to session
  • Draft data saved locally
  • Can be resumed across devices

Resume

Resuming validates session integrity:

  • Checks interview is in pausable state
  • Verifies no other active session exists
  • Loads latest draft data
  • Begins heartbeats immediately

Timeouts

Timeout rules:

  • 2 minutes without heartbeat → session considered stale
  • 24 hours in "created" → auto-pause
  • 7 days without activity → session cleanup

Multi-Tab Synchronization

Tab ownership is enforced via:

  • Single active tab per interview
  • Tab switch triggers heartbeat
  • Lost tab → automatic recovery

Offline Behaviour

Offline Edits

While offline:

  • Answers saved to local SQLite database
  • Interview state updated locally
  • Draft responses created/updated
  • Sync queue populated for later submission

Draft Saving

Draft saving strategy:

  • Every answered question triggers save
  • Position state stored with each answer
  • Conflict-free merge on sync
  • Retry logic for failed submissions

Sync

Sync process:

  • Queue processed on connectivity restoration
  • Conflicts detected and recorded
  • Responses submitted with idempotency
  • Interview status updated on success

Conflict Handling

Conflict detection:

  • HTTP 409 on push triggers conflict creation
  • Both versions preserved in SyncConflict
  • Interview status set to indicate conflict
  • Supervisor notification (future feature)

Sequence Diagrams

Normal Interview

Diagram; its source is available below
Diagram source
sequenceDiagram
    participant Enum as Enumerator
    participant FS as Form Service
    participant DS as Data Service
    participant SS as Sync Service

    Enum->>FS: POST /interviews (survey_id, respondent)
    FS-->>Enum: {id, session_token}

    loop Question Loop
        Enum->>FS: PATCH /interviews/{id} (answers)
        Note over FS: Update progress<br/>Save heartbeat
    end

    Enum->>FS: POST /interviews/{id}/complete
    FS->>DS: POST /responses (answers)
    DS-->>FS: {response_id}
    FS-->>Enum: Success

    Enum->>SS: POST /sync/push
    SS->>DS: Forward response
    DS-->>SS: 201 Created
    SS-->>Enum: Status completed

Rejected Interview

Diagram; its source is available below
Diagram source
sequenceDiagram
    participant Sup as Supervisor
    participant DS as Data Service
    participant Event as Event Bus
    participant FS as Form Service
    participant Enum as Enumerator

    Sup->>DS: PATCH /responses/{id}/reject
    Note over DS: Set status = rejected

    DS->>Event: Publish response.rejected
    Event-->>FS: Subscribe

    Note over FS: Lookup interview<br/>Set needs_revision<br/>Store response_id

Revision Resume

Diagram; its source is available below
Diagram source
sequenceDiagram
    participant Enum as Enumerator
    participant FS as Form Service

    Enum->>FS: GET /interviews/{id}
    Note over FS: Check needs_revision<br/>Return editable questions

    Enum->>FS: PATCH /interviews/{id}/transition
    Note over FS: Status → in_progress

    Enum->>FS: PATCH /responses/{id}/edit
    Note over FS: Apply corrections

State Diagram

Diagram; its source is available below
Diagram source
stateDiagram-v2
    [*] --> Created
    Created --> InProgress: Start Interview
    InProgress --> Paused: Pause
    InProgress --> Interrupted: System Error
    InProgress --> Completed: All Answered
    InProgress --> Terminated: Terminate
    Paused --> InProgress: Resume
    Interrupted --> InProgress: Recovery
    Completed --> NeedsRevision: Rejected
    NeedsRevision --> InProgress: Start Revision
    NeedsRevision --> Completed: Revision Done

Error Handling

Illegal Transitions

Invalid transitions return HTTP 400 with descriptive messages. Common invalid transitions:

  • Created → Completed (must go through In Progress)
  • Paused → Completed (must resume first)
  • Needs Revision → Terminated (revision required)

Stale Sessions

Stale session detection:

  • Heartbeat timeout triggers stale flag
  • New session requests denied if active exists
  • Supervisor can force session reset

Revision Failures

Revision failure handling:

  • Validation errors prevent transition
  • Original rejection reason preserved
  • Revision attempt logged

Sync Failures

Sync failure behavior:

  • Failed pushes remain in queue
  • Exponential backoff retry
  • Permanent failure after max attempts

Concurrent Edits

Concurrent edit handling:

  • Last-write-wins with conflict detection
  • Conflicts recorded for supervision
  • Interview state remains consistent

Performance Considerations

Heartbeat Frequency

  • 30-second intervals balance load and safety
  • Batch updates reduce database writes
  • Connection pooling handles concurrent heartbeats

Database Writes

Optimizations:

  • Single UPDATE per answer save
  • Progress tracked incrementally
  • Batch inserts for multiple answers

Polling

Client polling strategy:

  • Long polling for interview status
  • WebSocket consideration for future
  • Backoff on connection loss

Event Processing

Event processing:

  • Async handlers for non-critical updates
  • Dead letter queue for failures
  • Idempotent event handlers

Redis

Redis usage:

  • Session state cache
  • Heartbeat tracking
  • Queue management for sync