1. Introduction
The Single Audit implementation in the Audit-Lite application provides a streamlined approach for conducting audits by individual users. Unlike [team audits](../Team Audit/TeamAuditOverview.md), where multiple participants collaborate on different sections, single audits are designed for standalone use by a single auditor.
This documentation details the architecture, flows, and implementation specifics of the single audit feature, focusing on the questionnaire system, data management, and user experience.
2. Single Audit Workflow
The Single Audit process follows a comprehensive workflow from creation to completion:
2.1 Audit Initialization
The process begins when an auditor selects a site to audit and creates a new Single Audit:
sequenceDiagram participant User as Auditor participant App participant API participant DB as Database User->>App: Select "Create New Audit" User->>App: Select Site App->>API: POST /api/report/create {siteID, type: "single"} API->>DB: Create Audit Record DB-->>API: Return Audit ID API-->>App: Return Audit Data App-->>User: Display New Audit
The initialization creates a new audit record with the following state:
- Status: “in_progress”
- Progress: 0%
- Questions initialized with default values
- Timestamps for created/updated
2.1.1 Starting from Scheduled Audits
Many single audits begin from the schedule screen, where upcoming audits are listed:
sequenceDiagram participant User as Auditor participant Schedule as Schedule Screen participant Controller as StartReportController participant API as Backend API participant Router as Navigation Router User->>Schedule: View Scheduled Audits User->>Schedule: Select Site Schedule Schedule->>Controller: confirmStartReport(siteSchedule) Controller->>Controller: Open Confirmation Dialog User->>Controller: Confirm Start Audit Controller->>API: checkInReport(siteScheduleId) API-->>Controller: Return reportId and metadata Controller->>Router: Navigate to Questionnaire(reportId) Router->>User: Display Questionnaire Screen
The start report process involves:
- Schedule Selection: Choosing from pre-configured audit schedules
- Check-in Process: Creating a report record associated with the schedule
- Initialization: Setting up the questionnaire with the correct template
- Navigation: Taking the user to the first question
During initialization, the system checks:
- User permissions for the selected site
- Connectivity status (online/offline)
- Template availability
- Previous incomplete audits for the same site
2.2 Questionnaire Navigation
Auditors move through the questionnaire in sequence, providing responses and evidence:
stateDiagram-v2 [*] --> Question1 Question1 --> CompleteQ1: Answer CompleteQ1 --> Question2: Next Question2 --> CompleteQ2: Answer Question2 --> Question1: Previous CompleteQ2 --> Question3: Next Question3 --> Question2: Previous Question3 --> CompleteQ3: Answer CompleteQ3 --> Review: Submit Review --> [*]
Navigation is controlled by the useQuestionnaireNavigation hook, which provides:
onPressPrevious: Navigate to the previous questiononPressNext: Navigate to the next question or summary if on last questiononPressClear: Clear the current question’s answers and attachmentsonPressReview: Navigate to the summary screen
2.3 Question Types and Response Handling
The questionnaire supports various question types, each with specific UI and validation requirements:
| Question Type | Description | Validation |
|---|---|---|
| BINARY | Yes/No questions | Must select one option |
| BINARY_WITH_RED_FLAG | Yes/No with flag options | Must select option and flag if applicable |
| SCORE | Numeric scoring questions | Must provide valid score |
| MULTIPLE_CHOICE | Selection from options | Must select at least one option |
| CHECKLIST | Multiple selectable items | Optional selections |
| OPEN | Free text input | Length validation if applicable |
| NUMBER | Numeric input field | Range validation if applicable |
When a question is answered:
- The answer is validated against requirements
- Progress is automatically calculated and updated
- Changes are saved to local cache and synchronized
- Any conditional questions are dynamically shown or hidden
2.4 Attachment Management
Each question can specify requirements for different types of attachments:
graph TD A[Question] --> B{Requires Attachments?} B -->|Yes| C[Display Attachment Controls] B -->|No| D[Skip Attachment UI] C --> E[Photos] C --> F[Videos] C --> G[Documents] E --> H[Camera/Gallery Access] F --> I[Video Recording] G --> J[Document Picker] H --> K[Process and Store] I --> K J --> K K --> L[Display in UI] K --> M[Upload When Online]
Attachment specifications:
photoMinimum: Minimum number of photos requiredvideoLimit: Maximum number of videos alloweddocumentMinimum: Minimum number of documents required
Attachments are:
- Captured through device camera or selected from gallery/files
- Stored locally first with metadata (creation time, size, etc.)
- Uploaded to server when online (with retry mechanism)
- Accessible for review during the audit process
If an attachment is deleted:
- It is removed from the question’s attachment list
- The cached version is deleted
- The server is notified to remove it (if online)
- Progress is recalculated based on remaining attachments
2.5 Progress Tracking
Progress tracking is automatically calculated based on completion of questions:
flowchart TD A[User Answers Question] --> B[useActiveQuestionProgressTrigger] B --> C[Calculate Question Progress] C --> D[Update Progress State] D --> E[Update UI] C --> F[Save Progress to Cache] G[Initialize Questionnaire] --> H[useQuestionnaireProgressTrigger] H --> I[Calculate Overall Progress] I --> J[Update Progress State] J --> K[Update Progress UI]
Progress calculation considers:
- Answered required questions
- Completed attachment requirements
- Added required comments
- Completed conditional questions
The progress is displayed in the UI via a progress bar and percentage, helping auditors track their completion status.
2.5.1 Progress Calculation Logic
The progress calculation is handled by dedicated controllers that track completion of individual questions:
sequenceDiagram participant Form as Form State participant Trigger as Progress Trigger participant Usecase as Progress Usecase participant Atoms as Progress Atoms participant UI as User Interface participant Cache as Report Cache Note over Form,UI: User answers a question Form->>Trigger: Value changes Trigger->>Usecase: computeActiveQuestionProgress() Usecase->>Form: Get current question state Usecase->>Usecase: Apply validation rules Usecase->>Usecase: Update completion status Usecase->>Atoms: Update progress state Atoms->>UI: Reactive UI update Usecase->>Cache: Save progress data Note over Form,UI: Initial load or full recalculation Form->>Trigger: Initialize or recalculate Trigger->>Usecase: computeQuestionnaireProgress() Usecase->>Form: Get all questions state Usecase->>Usecase: Process each question Usecase->>Usecase: Count completed questions Usecase->>Usecase: Calculate percentage Usecase->>Atoms: Update overall progress Atoms->>UI: Update progress bar and count Usecase->>Cache: Save overall progress
The progress calculation uses a weighted approach:
- Question Weight Calculation:
- Each question has a base weight of 1
- Questions with required attachments get additional weight
- Questions with conditional sub-questions have increased weight
- Required questions are prioritized over optional ones
- Progress Detail Storage:
type QuestionnaireProgressDetail = Array<{
questionIndex: number;
isCompleted: boolean;
}>;
type QuestionnaireProgressState = {
progress: number; // Percentage (0-100)
count: number; // Completed questions count
total: number; // Total questions count
progressDetail: QuestionnaireProgressDetail;
flagCount: number; // Total flags count
flagColors: Array<{ color: string; count: number }>; // Flag breakdown
};- Optimization Techniques:
- Only recalculate affected questions when possible
- Caching of intermediate results
- Memoization of complex calculations
2.5.2 Progress UI Components
The progress is visualized through multiple UI components:
- Top Progress Bar:
- Horizontal bar showing overall completion percentage
- Color coding to indicate completion status:
- Red: <50% complete
- Yellow: 50-80% complete
- Green: >80% complete
- Animated transitions when progress changes
- Summary Statistics:
- Questions answered: X/Y (with percentage)
- Required questions completed: X/Y
- Flags raised: X (breakdown by color)
- Attachments added: X (breakdown by type)
- Question-Level Indicators:
- Checkmark for completed questions
- Warning icon for incomplete required questions
- Badge showing conditional questions status
- Navigation Assists:
- “Jump to next incomplete” functionality
- Filtering options to show only incomplete questions
- Section completion indicators
Progress tracking is tightly integrated with the form state and validation system, ensuring that the displayed progress accurately reflects the audit’s completion status in real-time.
2.6 Review and Submission
Before finalization, the audit undergoes a comprehensive review:
flowchart TD A[Open Summary Screen] --> B{Complete?} B -->|Incomplete Items| C[Highlight Incomplete] C --> D[Navigate to Incomplete] D --> A B -->|All Complete| E[Review Responses] E --> F[Review Attachments] F --> G[Review Flags/Priorities] G --> H[Submit Audit] H --> I[Generate Report] I --> J[Notify Stakeholders]
During review:
- Completion percentage is verified (ideally 100%)
- Incomplete questions are highlighted for completion
- All attachments are verified
- Flags and priorities are confirmed
- Summary statistics are compiled
- Final submission processes the audit for reporting
2.6.1 Summary Screen Features
The summary screen provides comprehensive overview and finalization options:
graph TD A[Summary Screen] --> B[Completion Status] A --> C[Question List] A --> D[Flag Summary] A --> E[Attachment Summary] A --> F[Action Buttons] B --> B1[Progress Bar] B --> B2[Percentage Complete] B --> B3[Required vs Optional Status] C --> C1[Sectioned Question List] C --> C2[Completion Status Indicators] C --> C3[Quick Navigation Links] D --> D1[Red Flags Count] D --> D2[Yellow Flags Count] D --> D3[Green Flags Count] E --> E1[Photos Count] E --> E2[Videos Count] E --> E3[Documents Count] F --> F1[Submit Button] F --> F2[Return to Questionnaire] F --> F3[Save Draft]
Key summary screen functionality:
- Question Navigation: Users can tap on any question to navigate directly to it for editing
- Completion Validation:
- Visual indicators show completion status of each question
- Required but incomplete questions are highlighted in red
- Warning shown if attempting to submit with incomplete required questions
- Flag Analysis:
- Breakdown of flags by color and priority
- Quick navigation to flagged items
- Option to add notes to flagged items
- Attachment Review:
- List of all attachments grouped by question
- Thumbnail previews of photos and videos
- File size and type information for documents
- Option to add, replace, or delete attachments
- Final Actions:
- Submit: Complete the audit and generate report
- Save Draft: Store current state without finalizing
- Sync: Synchronize data and generate JSON export (feature flag controlled)
2.6.2 JSON Data Export
When the EXPORT_JSON_REPORT_ON_SUBMIT_SYNC feature flag is enabled, the sync process includes automatic JSON export:
sequenceDiagram participant User participant SubmitController as SubmitQuestionnaireController participant ExportUseCase as AuditDataExportUseCase participant FileSystem participant Server User->>SubmitController: Click Submit SubmitController->>SubmitController: Validate Report SubmitController->>SubmitController: Check Feature Flag alt Feature Flag Enabled SubmitController->>ExportUseCase: exportAuditData(reportData) ExportUseCase->>FileSystem: Save JSON to Device FileSystem-->>SubmitController: Export Result Note over SubmitController: Log export result (non-blocking) end SubmitController->>Server: Upload Report Server-->>SubmitController: Submission Confirmed SubmitController-->>User: Navigate to Payoff
Export Features:
- Automatic Export: JSON file automatically generated during sync
- Complete Data: Exports the full
ReportFormobject with all questions and answers - Non-Blocking: Export failures don’t prevent submission
- Platform Support: Android SAF, iOS sharing, Web download
- File Naming:
report_[reportID]_[timestamp].json
Exported Data Structure:
{
"questions": [...],
"sections": [...],
"status": "complete",
"site": "site_id",
"auditor": "user_id",
"datetimeSubmitted": "2025-01-19T10:30:00Z",
"questionnaire": "questionnaire_id",
"grade": "A",
"maxScore": 100,
// ... complete report data
}Upon submission:
- A final validation check is performed
- Confirmation dialog verifies user intent
- All data is synchronized to the server
- JSON export initiated during sync (if feature flag enabled)
- Report generation begins in the background
- User is directed to the payoff screen
- Notifications are sent to stakeholders
- Audit is marked as complete in the database
3. Architecture Overview
The Single Audit feature follows a modular architecture pattern:
graph TD A[Single Audit Entry Point] --> B[Questionnaire Screen] B --> C[Questionnaire Component] C --> D[Questionnaire Form] D --> E[Question Container] E --> F[Individual Questions] B --- G[Controllers] G --> H[Screen Controller] G --> I[Navigation Controller] G --> J[Progress Controller] G --> K[Attachment Controllers] B --- L[State Management] L --> M[Form State] L --> N[Navigation State] L --> O[Progress State] L --> P[Attachment State]
3.1 Component Structure
Key components in the hierarchy:
| Component | Purpose | File Path |
|---|---|---|
| QuestionnaireScreen | Entry point | packages/app/features/questionnaire/screen.tsx |
| Questionnaire | Main container | packages/app/features/questionnaire/questionnaire/questionnaire.tsx |
| QuestionnaireForm | Keyboard-aware form | packages/app/features/questionnaire/questionnaire/questionnaire-form.tsx |
| QuestionnaireQuestionContainer | Question renderer | packages/app/features/questionnaire/questionnaire/questionnaire-question-container.tsx |
| QuestionnaireQuestion | Individual question UI | packages/app/features/questionnaire/questionnaire/questionnaire-question.tsx |
| QuestionnaireSummary | Review screen | packages/app/features/questionnaire/questionnaire-summary/screen.tsx |
3.2 State Management
The Single Audit uses Jotai for state management with several key atoms:
graph TD A[State Atoms] --> B[Form State] A --> C[UI State] A --> D[Navigation State] B --> E[questionnaireFormAtom] C --> F[isRecommendationOpenAtom] C --> G[addedRemediesAtom] D --> H[activeQuestionIndexAtom] I[Progress State] --> J[questionnaireProgressAtom]
These atoms provide:
- Reactive updates to the UI
- Easy state sharing across components
- Optimized rendering through selective updates
3.3 Controllers
Controllers handle business logic and data management:
| Controller | Purpose | File Path |
|---|---|---|
| QuestionnaireScreenController | Initialize questionnaire | packages/app/features/questionnaire/questionnaire/controllers/questionnaire-screen-controller.ts |
| QuestionnaireNavigationController | Navigation between questions | packages/app/features/questionnaire/questionnaire/controllers/questionnaire-navigation.ts |
| QuestionnaireProgressController | Track completion | packages/app/features/questionnaire/questionnaire/controllers/questionnaire-progress.ts |
| QuestionnairePhotoController | Handle photo attachments | packages/app/features/questionnaire/questionnaire/controllers/questionnaire-photo.ts |
| QuestionnaireVideoController | Handle video attachments | packages/app/features/questionnaire/questionnaire/controllers/questionnaire-video.ts |
| QuestionnaireDocumentsController | Handle document attachments | packages/app/features/questionnaire/questionnaire/controllers/questionnaire-documents.ts |
4. Core Flows
4.1 Navigation Flow
sequenceDiagram participant User participant UI as User Interface participant Nav as Navigation Controller participant State as State Management participant Form as Form State User->>UI: Press Next Button UI->>Nav: onPressNext() Nav->>State: Check if Last Question alt Last Question State-->>Nav: Yes, Last Question Nav->>State: Save Form State Nav->>UI: Navigate to Summary else Not Last Question State-->>Nav: Not Last Question Nav->>State: Increment Question Index State->>UI: Render Next Question end User->>UI: Press Previous Button UI->>Nav: onPressPrevious() Nav->>State: Check if First Question alt First Question State-->>Nav: Yes, First Question Nav->>UI: Stay on First Question else Not First Question State-->>Nav: Not First Question Nav->>State: Decrement Question Index State->>UI: Render Previous Question end User->>UI: Press Clear Button UI->>Nav: onPressClear() Nav->>Form: Reset Current Question Data Form->>State: Update Form State State->>UI: Render Empty Question
The navigation flow ensures auditors can move through questions in a logical sequence, clearing responses when needed, and reviewing their work before submission.
4.2 Form State Management
The questionnaire uses React Hook Form for form state management:
graph TD A[Initialize Form] --> B[FormProvider] B --> C[Component Tree] C --> D[Question Components] D --> E[Input Fields] E --> F[onChange Events] F --> G[Form State Updates] G --> H[Validation] H --> I[Error States] G --> J[Progress Calculation] J --> K[Progress Updates] G --> L[Debounced Cache] L --> M[Report Service] M --> N[Server Sync]
Form values are structured hierarchically:
- Top level: Report metadata (ID, type, progress)
- Questions array: Contains all question data
- Each question: Type, content, answer, attachments, etc.
- Conditional questions: Nested within parent questions
4.3 Attachment Handling
Attachments (photos, videos, documents) follow this workflow:
sequenceDiagram participant User participant Question as Question UI participant Controller as Attachment Controller participant Storage as Local Storage participant API as Server API User->>Question: Add Attachment Question->>Controller: Request Camera/Gallery alt Camera Controller->>User: Open Camera User->>Controller: Capture Media else Gallery Controller->>User: Open Gallery User->>Controller: Select Media end Controller->>Storage: Save to Local Path Controller->>Question: Update UI with Attachment alt Online Mode Controller->>API: Upload Attachment API-->>Controller: Return Attachment ID Controller->>Storage: Update with Server ID else Offline Mode Controller->>Storage: Queue for Upload end User->>Question: Remove Attachment Question->>Controller: Delete Request Controller->>Storage: Remove Local File Controller->>API: Delete from Server (if online)
When internet connectivity resumes after offline usage:
- Queued attachments are automatically uploaded
- Local paths are updated with server identifiers
- Sync status indicators show completion
4.3.1 Attachment Error Handling
When dealing with attachments, various errors can occur, which are handled systematically:
flowchart TD A[Attachment Operation] --> B{Permission Check} B -->|Granted| C[Prepare Media Operation] B -->|Denied| D[Display Permission Dialog] D --> E{User Response} E -->|Grant Permission| B E -->|Deny Permission| F[Show Error Message] C --> G{Operation Type} G -->|Capture Photo| H[Camera Interface] G -->|Record Video| I[Video Interface] G -->|Select Document| J[Document Picker] H --> K{Capture Result} I --> K J --> K K -->|Success| L[Process Media] K -->|Failure| M[Handle Specific Error] K -->|User Cancel| N[Return to Question] M --> M1[Show Error Message] M --> M2[Log Error Details] M --> M3[Offer Retry Option] L --> O{Storage Space Check} O -->|Sufficient| P[Save to Local Storage] O -->|Insufficient| Q[Show Storage Error] P --> R{Upload Check} R -->|Online| S[Upload to Server] R -->|Offline| T[Queue for Later Upload] S --> U{Upload Result} U -->|Success| V[Update Attachment Metadata] U -->|Failure| W[Retry Logic] W --> W1{Retry Count} W1 -->|< Max Retries| X[Wait and Retry] W1 -->|>= Max Retries| Y[Add to Error List] X --> S Y --> Y1[Show Sync Error] Y --> Y2[Provide Manual Retry Option]
4.3.2 Attachment Storage
Attachments are stored in a structured way to ensure efficient access and synchronization:
- Local Storage Structure:
- Directory created for each audit
- Subdirectories for questions
- Files named with unique identifiers
- Example path:
/auditData/{reportId}/q{questionIndex}/{timestamp}_{fileType}.{extension}
- Metadata Storage:
- Each attachment has metadata stored in the form state
- Metadata includes:
- Local URI
- Server ID (when uploaded)
- Creation timestamp
- File size and dimensions
- Upload status
- Sync status
- Storage Limitations:
- Each question can specify maximum counts for different attachment types
- System enforces size limits for different media types:
- Photos: 10MB per image
- Videos: 100MB total, 30 seconds maximum duration
- Documents: 25MB per file
- Deletion Handling:
- When an attachment is deleted:
- Local file is removed immediately
- Server delete request is queued if offline
- Form state is updated to remove reference
- Progress is recalculated
4.4 Online/Offline Mode
The Single Audit supports both online and offline operation:
graph TD A[App Start] --> B{Check Connectivity} B -->|Online| C[Standard Operation] B -->|Offline| D[Offline Mode] C --> E[Real-time Sync] C --> F[Direct Attachment Upload] C --> G[Live Data Fetching] D --> H[Local Storage] D --> I[Sync Queue] D --> J[Cached Data] H --> K{Connectivity Restored?} I --> K J --> K K -->|Yes| L[Background Sync] K -->|No| M[Continue Offline] L --> N[Upload Queued Data] L --> O[Fetch Updates] L --> P[Resolve Conflicts]
During offline operation:
- All data is stored locally first
- UI indicates offline status
- Attachments are stored locally
- Progress is tracked normally
- When connectivity is restored, data is synchronized
4.4.1 Synchronization Mechanism
The application implements a robust synchronization system to handle offline operations:
sequenceDiagram participant App participant Cache as Local Cache participant SyncQueue as Sync Queue participant API as Backend API participant Conflict as Conflict Resolution Note over App,Cache: Offline Mode App->>Cache: Save Question Answer App->>SyncQueue: Queue Change for Sync App->>Cache: Store Attachment Locally Note over App,API: Connection Restored App->>API: Check Connection App->>SyncQueue: Process Queued Changes loop For Each Queued Item SyncQueue->>API: Send Update alt Successful Sync API-->>SyncQueue: Confirm Update SyncQueue->>Cache: Clear Item from Queue else Sync Conflict API-->>SyncQueue: Return Conflict SyncQueue->>Conflict: Resolve Conflict Conflict->>API: Send Resolved Data end end App->>Cache: Update Local Cache with Server Data
Key synchronization features:
- Change Tracking: Every modification is tracked with timestamps and change types
- Queued Operations: Changes are stored in a FIFO queue during offline mode
- Batch Processing: Multiple changes are processed in batches when connection is restored
- Conflict Resolution:
- Last-write-wins for simple conflicts
- Merge strategy for non-overlapping changes
- User intervention for critical conflicts
- Attachment Handling:
- Photos, videos, and documents are stored locally with metadata
- Background upload of attachments when connectivity is restored
- Progress tracking for uploads
- Retry mechanism for failed uploads
The sync status is clearly indicated in the UI:
- Sync indicator in the header shows online/offline status
- Individual questions show sync status (synced, pending, conflict)
- Attachments display upload status and progress
- Toast notifications for sync completion and errors
5. Data Models
5.1 Question Model
The core building block is the Question type:
interface Question {
content: string;
type: QuestionTypes;
answer: string | number;
answers: string[];
comment: string;
photos: AttachmentMetadata[];
videos: AttachmentMetadata[];
documents: AttachmentMetadata[];
category?: string;
reference?: string;
answerRequired?: boolean;
commentRequired?: boolean;
photoMinimum?: number;
videoLimit?: number;
documentMinimum?: number;
isConditional?: boolean;
conditionalQuestion?: ConditionalQuestion;
redFlag?: boolean;
flagColor?: string;
priority?: string;
uom?: string;
}5.2 Form Structure
The QuestionnaireFormValues mirrors the ReportForm entity:
type ReportForm = {
id: string;
siteID: string;
auditType: "single" | "team";
status: ReportStatus;
totalQuestions: number;
totalAnswered: number;
createdAt: string;
updatedAt: string;
completedAt?: string;
questions: Question[];
questionnaireProgress?: number;
questionnaireProgressDetail?: Array<{
questionIndex: number;
isCompleted: boolean;
}>;
questionnaireFlags?: {
flagCount: number;
flagColors: Array<{ color: string; count: number }>;
};
};5.3 Attachment Types
Media attachments use specialized metadata:
type AttachmentMetadata = {
id: string;
uri: string;
name: string;
type: "image" | "video" | "document";
size?: number;
width?: number;
height?: number;
duration?: number;
createdAt: string;
status: "pending" | "uploading" | "uploaded" | "failed";
progress?: number;
error?: string;
};6. Implementation Details
6.1 Conditional Questions
The questionnaire supports conditional questions that appear based on answers to parent questions:
graph TD A[Parent Question] --> B{Answer Selected} B -->|Option A| C[Show Conditional Questions Set A] B -->|Option B| D[Show Conditional Questions Set B] B -->|Other| E[No Conditional Questions]
Implementation details:
- Parent questions have an
isConditionalflag conditionalQuestion.conditionsobject maps answers to question arrays- Conditional rendering in
QuestionnaireQuestionContainer - Progress calculation includes conditional questions
6.2 Validation Logic
The questionnaire implements several validation rules:
flowchart TD A[Question Validation] --> B{Required Answer?} B -->|Yes| C{Answer Provided?} B -->|No| D[Mark as Valid] C -->|Yes| E{Attachment Requirements} C -->|No| F[Mark as Invalid] E -->|Met| G{Comment Requirements} E -->|Not Met| H[Mark as Invalid]
Key validation aspects:
- Required answers based on
answerRequiredflag - Required attachments based on minimum counts
- Comment requirements based on question type
- Validation integrated with progress tracking
6.2.1 Question Type-Specific Validation
Each question type has specific validation rules to ensure data integrity:
| Question Type | Validation Logic | Required Elements |
|---|---|---|
| BINARY | Must select “Yes” or “No” | Single selection |
| BINARY_WITH_RED_FLAG | Must select option and appropriate flag if answer is “No” | Selection and flag selection |
| SCORE | Value must be within defined min/max range | Numeric value |
| MULTIPLE_CHOICE | At least one option must be selected (if required) | One or more selections |
| CHECKLIST | No validation unless marked as required | Selections as specified |
| OPEN | Text length must be between min/max if specified | Text input |
| NUMBER | Value must be numeric and within range if specified | Numeric value within bounds |
| DATE_TIME | Must be a valid date/time and within allowed range if specified | Valid date and time |
6.2.2 Validation Code Implementation
The validation logic is implemented in the progress calculation and consists of multiple checks:
// Simplified validation logic (pseudo-code)
function isQuestionComplete(question: Question): boolean {
// Check for required answer
if (question.answerRequired && !hasValidAnswer(question)) {
return false;
}
// Check for required attachments
if (!hasRequiredAttachments(question)) {
return false;
}
// Check for required comments
if (question.commentRequired && !question.comment) {
return false;
}
// Check for conditional questions
if (question.isConditional && hasActiveConditionals(question)) {
const conditionals = getActiveConditionalQuestions(question);
return conditionals.every((q) => isQuestionComplete(q));
}
return true;
}
function hasValidAnswer(question: Question): boolean {
switch (question.type) {
case "BINARY":
case "BINARY_WITH_RED_FLAG":
return question.answer === "yes" || question.answer === "no";
case "SCORE":
return (
typeof question.answer === "number" &&
question.answer >= question.minValue &&
question.answer <= question.maxValue
);
case "MULTIPLE_CHOICE":
return Array.isArray(question.answers) && question.answers.length > 0;
case "CHECKLIST":
return (
!question.answerRequired ||
(Array.isArray(question.answers) && question.answers.length > 0)
);
case "OPEN":
return (
!!question.answer &&
(!question.minLength || question.answer.length >= question.minLength) &&
(!question.maxLength || question.answer.length <= question.maxLength)
);
case "NUMBER":
return (
typeof question.answer === "number" &&
(!question.minValue || question.answer >= question.minValue) &&
(!question.maxValue || question.answer <= question.maxValue)
);
default:
return !!question.answer;
}
}
function hasRequiredAttachments(question: Question): boolean {
const { photoMinimum, videoLimit, documentMinimum } = question;
if (
photoMinimum &&
(!question.photos || question.photos.length < photoMinimum)
) {
return false;
}
if (
videoLimit &&
videoLimit > 0 &&
(!question.videos || question.videos.length < videoLimit)
) {
return false;
}
if (
documentMinimum &&
(!question.documents || question.documents.length < documentMinimum)
) {
return false;
}
return true;
}6.2.3 User Feedback
When validation fails, the system provides immediate feedback:
- Visual indicators highlight incomplete or invalid fields
- Error messages explain specific requirements
- The “Next” button may be disabled until validation passes for critical fields
- Warning prompts appear when trying to proceed with incomplete required fields
- Progress indicators reflect the validation status
6.3 Flag and Priority Handling
Questions can be flagged with different colors to indicate status:
pie title Audit Flag Distribution "Green Flags" : 42 "Yellow Flags" : 28 "Red Flags" : 15
Flags are used to:
- Highlight critical safety issues (red flags)
- Indicate potential compliance risks (yellow flags)
- Mark items meeting or exceeding standards (green flags)
Priorities can be assigned as:
- Critical (immediate action required)
- High (action needed within 24 hours)
- Medium (action needed within 7 days)
- Low (action needed within 30 days)
7. API Reference
The Single Audit interacts with several endpoints:
| API Endpoint | Purpose | Controller |
|---|---|---|
GET /api/[questionnaire](../../Questionnaires/QuestionnairesOverview.md)/{firebaseReportID} | Fetch questionnaire data | useQuestionnaireData() |
PATCH /api/[report](../../Reports/ReportsOverview.md)/{firebaseReportID} | Update report data | reportService.updateCache() |
GET /api/organization/priorities | Get priority settings | useOrganizationPrioritiesQuery() |
GET /api/reference/{referenceId} | Fetch reference material | ReferenceViewer |
POST /api/attachment/upload | Upload attachment | questionnairePhotoController |
GET /api/attachment/{attachmentId} | Get attachment | questionnaireDocumentController |
GET /api/user/audits | Get user audits | useAuditsQuery() |
POST /api/[report](../../Reports/ReportsOverview.md)/create | Create new report | reportService.createReport() |
8. File Path Reference
9. Questionnaire Routes
The questionnaire feature in the Audit-Lite application follows a specific navigation flow through various screens:
| Route | Purpose | Screen Component |
|---|---|---|
/[questionnaire](../../Questionnaires/QuestionnairesOverview.md) | Main questionnaire entry point | QuestionnaireScreen |
/[questionnaire](../../Questionnaires/QuestionnairesOverview.md)/summary | Review and submit completed questionnaire | QuestionnaireSummaryScreen |
/[questionnaire](../../Questionnaires/QuestionnairesOverview.md)/reference-viewer | View reference materials and documentation | ReferenceViewerScreen |
/[questionnaire](../../Questionnaires/QuestionnairesOverview.md)/payoff | Post-completion screen with next steps | PayoffScreen |
/[questionnaire](../../Questionnaires/QuestionnairesOverview.md)/signature | Sign and finalize completed audit | SignatureScreen |
/[questionnaire](../../Questionnaires/QuestionnairesOverview.md)/overview | Overview of entire questionnaire | QuestionnaireOverviewScreen |
Each route accepts query parameters that include:
siteID: The ID of the site being auditedfirebaseReportID: The ID of the report in FirebaseauditType: Type of audit (‘single’ or ‘team’)sectionIndex: Section index (only used in [team audits](../Team Audit/TeamAuditOverview.md))
10. Dependencies
The Single Audit implementation uses several key packages:
| Package | Purpose |
|---|---|
| React Hook Form | Form state management |
| Jotai | Atomic state management |
| React Navigation | Screen navigation |
| KeyboardAwareScrollView | Keyboard management |
| TanStack Query | Data fetching and caching |
| Lodash | Utility functions (debounce, etc.) |
| Expo Camera/Image Picker | Media capture |
| Document Picker | File selection |
| Burnt | Toast notifications |
| MMKV | Local storage |